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

# Quickstart

> Install Swarmd into a Kubernetes cluster and sign in — about ten minutes, most of it waiting for pods.

# Quickstart

By the end you'll have the full platform running in your cluster and be
signed in to the UI as your first admin user.

<Info>
  Need the prerequisites? [Overview → What you need](/self-hosting/overview#what-you-need).
  The short version: a cluster with a default StorageClass, Helm 3, and a
  licence key.

  Don't have a key yet? Licences are issued per deployment —
  [talk to us](https://swarmd.ai/contact) and we'll size the tier and get you
  one. There is no self-serve path, and the cluster cannot pull Swarmd's images
  without it.
</Info>

***

## Step 1: Store your licence key

You *can* pass the key with `--set licence.key=...`, and for a throwaway test
that's fine. Don't do it for anything else: `--set` values are recorded in
Helm's release history and visible to anyone who can run `helm get values`.

Put it in a Secret instead:

```bash theme={null}
kubectl create namespace swarmd

kubectl -n swarmd create secret generic swarmd-licence \
  --from-literal=value='LIC-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
```

<Warning>
  `licence.key` and `licence.existingSecretRef.name` are **mutually exclusive**.
  Setting both fails the install with a named error rather than silently
  preferring one.
</Warning>

***

## Step 2: Install the chart

```bash theme={null}
helm install swarmd deployments/h7s/swarmd \
  --namespace swarmd \
  --set licence.existingSecretRef.name=swarmd-licence
```

That's the whole command. Everything else has a working default.

<Accordion title="What just happened, in order">
  1. **Validation runs first.** The chart checks every combination it knows to
     be broken — a missing external URL, an unknown `postgres.mode`, SMTP
     enabled without credentials — and refuses to render with a specific
     message. Nothing reaches your cluster until it passes.
  2. **A pre-install Job fetches ECR credentials.** It calls the licence server
     with your key and writes the result as a `dockerconfigjson` Secret. This
     has to succeed before anything else — without it the cluster cannot pull
     Swarmd's images. See [Licence and images](/self-hosting/licence-and-images).
  3. **A credentials Secret is generated.** Postgres, Keycloak admin and
     ClickHouse passwords, plus an encryption key — 24 random alphanumeric
     characters each.
  4. **Postgres and Keycloak start**, and a bootstrap Job loads the Swarmd realm.
  5. **Migration Jobs run Flyway**, then the services and UI roll out.
</Accordion>

***

## Step 3: Watch it come up

```bash theme={null}
kubectl -n swarmd get pods -w
```

Expect every pod `Ready` in about **three minutes** on a fresh cluster —
longer on first pull, since the images come from ECR.

```
NAME                                  READY   STATUS      RESTARTS   AGE
swarmd-licence-ecr-bootstrap-x9k      0/1     Completed   0          3m
swarmd-postgres-df9c7b8d4-2kx9n       1/1     Running     0          3m
swarmd-keycloak-7c4f8b6d9-mn2rt       1/1     Running     0          3m
swarmd-registry-migrate-p4l2n         0/1     Completed   0          2m
swarmd-registry-5b7d8f9c6-tz8yu       1/1     Running     0          2m
swarmd-registry-worker-7f9b2c4d8-kk1  1/1     Running     0          2m
swarmd-audit-migrate-h7z9x            0/1     Completed   0          2m
swarmd-audit-6c4d8f9b7-mm3nn          1/1     Running     0          2m
swarmd-audit-worker-9d7f6c5b4-pp8qq   1/1     Running     0          2m
...
swarmd-gateway-6d8f9c7b5-qw3er        1/1     Running     0          2m
swarmd-platform-ui-8f9c7b6d5-ax2z     1/1     Running     0          2m
```

<Note>
  **Three workloads per DB-backed service is expected**, not a mistake: a
  `-migrate` Job that runs Flyway once and exits, the API pod, and a `-worker`
  pod running schedulers and outbox drainers. A default install is 18
  Deployments. See
  [Scaling: core and worker](/self-hosting/configuration#scaling-core-and-worker)
  for why, and how to collapse it on a laptop.
</Note>

<AccordionGroup>
  <Accordion title="Pods stuck in ImagePullBackOff">
    The licence loop failed. Check the bootstrap Job first — it's the only thing
    that can create the pull secret:

    ```bash theme={null}
    kubectl -n swarmd logs job/swarmd-licence-ecr-bootstrap
    ```

    The usual causes are a mistyped key, a licence that has expired or been
    revoked, and no cluster egress to the licence server. Full breakdown in
    [Licence and images](/self-hosting/licence-and-images#when-it-goes-wrong).
  </Accordion>

  <Accordion title="Postgres pod Pending">
    Almost always storage. `kubectl -n swarmd describe pvc` will say so —
    typically no default StorageClass, or a `storageClass` name that doesn't
    exist on this cluster:

    ```bash theme={null}
    kubectl get storageclass
    helm upgrade swarmd ... --set postgres.storage.storageClass=gp3
    ```
  </Accordion>

  <Accordion title="The install failed before creating anything">
    That's the validation gate, and the message names the exact value to fix.
    It runs before any resource is created, so there's nothing to clean up —
    correct the value and re-run.
  </Accordion>
</AccordionGroup>

***

## Step 4: Get in

Ingress is off by default, so port-forward:

```bash theme={null}
kubectl -n swarmd port-forward svc/swarmd-platform-ui 3000:80
```

Open **[http://localhost:3000](http://localhost:3000)** and create your tenant and first admin user
through the sign-up flow.

<Warning>
  **Email is off by default.** Sign-up works, but verification, password-reset
  and invite emails are logged and dropped — nobody receives them. Fine for a
  first look; wire up [SMTP](/self-hosting/configuration#smtp) before you invite
  anyone real.
</Warning>

You'll also want the API gateway reachable — it's what agents and SDKs talk to:

```bash theme={null}
kubectl -n swarmd port-forward svc/swarmd-gateway 8080:80
```

```bash theme={null}
curl http://localhost:8080/registry/v1/agents -H "Authorization: Bearer $TOKEN"
```

Ready for real hostnames instead? → [Ingress](/self-hosting/ingress).

<Accordion title="Getting the Keycloak admin password">
  The chart generates it. To reach the Keycloak admin console directly:

  ```bash theme={null}
  kubectl -n swarmd get secret swarmd-generated-credentials \
    -o jsonpath='{.data.keycloak-admin-password}' | base64 -d
  ```

  The username is in the same Secret under `keycloak-admin-username`. You
  rarely need this — Swarmd manages realm objects for you — but it's there for
  debugging identity-provider setup.
</Accordion>

***

## Step 5: Point an SDK at it

Your install is a complete Swarmd platform, so the SDKs work against it
unchanged — you just override the two URLs:

```bash .env theme={null}
SWARMD_AGENT_ID=<from registering an agent>
SWARMD_CLIENT_SECRET=<...>
SWARMD_BASE_URL=https://api.your-domain.example
SWARMD_TOKEN_URL=https://auth.your-domain.example/realms/swarmd/protocol/openid-connect/token
```

<Note>
  Both URLs must point at the **same** install. A base URL from one environment
  with a token URL from another mints tokens the gateway rejects on audience —
  a `401` that looks like a bad secret but isn't.
</Note>

From there the [Python SDK](/sdks/python/overview) and the
[TypeScript channel client](/sdks/typescript/channel-client) apply exactly as
written.

***

## Step 6: Make it real

The default install is deliberately minimal — it boots anywhere, needs no
external accounts, and stores everything in one in-cluster Postgres. Before
production:

<CardGroup cols={2}>
  <Card title="Pick a database layout" icon="database" href="/self-hosting/databases">
    One Postgres, one per service, or your own managed instance.
  </Card>

  <Card title="Set up ingress and TLS" icon="lock" href="/self-hosting/ingress">
    Traefik or AWS Load Balancer Controller.
  </Card>

  <Card title="Turn on SMTP" icon="envelope" href="/self-hosting/configuration#smtp">
    Without it, no user can verify an address or accept an invite.
  </Card>

  <Card title="Start from a preset" icon="layer-group" href="/self-hosting/presets">
    Eight tested shapes, laptop through hardened production.
  </Card>
</CardGroup>

***

## Uninstalling

```bash theme={null}
helm uninstall swarmd -n swarmd
```

<Warning>
  PVCs and the generated credentials Secret **survive** on purpose — the Secret
  carries `helm.sh/resource-policy: keep`, so a reinstall reuses the same
  passwords and your data is still there. To destroy the data too:

  ```bash theme={null}
  kubectl -n swarmd delete pvc --all
  kubectl -n swarmd delete secret swarmd-generated-credentials
  ```

  That is irreversible.
</Warning>
