---
title: "Reference"
description: "Every command, argument and flag."
url: "https://saved.sh/docs/cli/reference"
---

Arguments in `UPPER_CASE` are required positionals. **IDs, not names**, everywhere except a
manifest.

## Global [#global]

```bash
sctl [command] --help
```

| Flag            | Default                | Environment variable |
| --------------- | ---------------------- | -------------------- |
| `--backend-url` | `https://api.saved.sh` | `SCTL_BACKEND_URL`   |

| Environment variable | Purpose                                                     |
| -------------------- | ----------------------------------------------------------- |
| `SCTL_ACCESS_TOKEN`  | Session token or API key. Overrides the config file         |
| `SCTL_WORKSPACE_ID`  | Which workspace to act on. Required for machine credentials |
| `SCTL_BACKEND_URL`   | Which environment to talk to                                |

Config file location:

| Platform | Path                                             |
| -------- | ------------------------------------------------ |
| Linux    | `~/.config/sctl/config.yaml`                     |
| macOS    | `~/Library/Application Support/sctl/config.yaml` |
| Windows  | `%AppData%\sctl\config.yaml`                     |

## Authentication [#authentication]

| Command            | Description                                              |
| ------------------ | -------------------------------------------------------- |
| `sctl login`       | Sign in with a device code                               |
| `sctl auth whoami` | Show the signed-in user, workspace, role and permissions |

## Workspaces [#workspaces]

| Command                           | Description                                 |
| --------------------------------- | ------------------------------------------- |
| `sctl workspace list`             | Your workspaces                             |
| `sctl workspace create NAME`      | Create one and become its admin             |
| `sctl workspace switch WORKSPACE` | Re-scope the session. Takes an id or a name |
| `sctl workspace current`          | The workspace this session acts on          |

Aliases: `sctl ws`.

## Members [#members]

| Command                               | Description                                                      |
| ------------------------------------- | ---------------------------------------------------------------- |
| `sctl member list`                    | Members and their roles                                          |
| `sctl member invite EMAIL [ROLE]`     | Invite. Omitting `ROLE` means `member`, which has no permissions |
| `sctl member role MEMBERSHIP_ID ROLE` | Change a member's role                                           |
| `sctl member remove MEMBERSHIP_ID`    | Remove a member                                                  |
| `sctl member invitations`             | Pending invitations                                              |
| `sctl member resend INVITATION_ID`    | Send it again                                                    |
| `sctl member revoke INVITATION_ID`    | Cancel it                                                        |

## Roles [#roles]

| Command                 | Flags               | Description                     |
| ----------------------- | ------------------- | ------------------------------- |
| `sctl role list`        |                     | Roles and their permissions     |
| `sctl role create NAME` | `--desc`, `--perms` | Create a custom role            |
| `sctl role update SLUG` | `--desc`, `--perms` | **Replaces** the permission set |
| `sctl role delete SLUG` |                     | Delete a custom role            |

`--perms` is comma-separated permission slugs.

## API keys [#api-keys]

| Command                     | Flags                | Description                            |
| --------------------------- | -------------------- | -------------------------------------- |
| `sctl apikey create NAME`   | `--perms` (required) | Create a key, printing the secret once |
| `sctl apikey list`          |                      | Keys and their permissions             |
| `sctl apikey revoke KEY_ID` |                      | Revoke a key                           |

Alias: `sctl key`.

## Workers [#workers]

| Command                        | Description                            |
| ------------------------------ | -------------------------------------- |
| `sctl worker provision NAME`   | Create a worker, printing its key once |
| `sctl worker list`             | Workers, with IDs                      |
| `sctl worker rotate WORKER_ID` | New key, same worker ID                |
| `sctl worker delete WORKER_ID` | Revoke permanently                     |

## Backups [#backups]

| Command                               | Description                                            |
| ------------------------------------- | ------------------------------------------------------ |
| `sctl backup list`                    | Backups, with IDs, kinds, states and schedules         |
| `sctl backup create NAME --kind KIND` | Create a draft. `KIND` is `local`, `cloud` or `manual` |
| `sctl backup configure BACKUP_ID`     | Configure. Omitted flags are left alone                |
| `sctl backup trigger BACKUP_ID`       | Run now, outside the schedule                          |
| `sctl backup pause BACKUP_ID`         | Suspend the schedule                                   |
| `sctl backup resume BACKUP_ID`        | Resume it                                              |
| `sctl backup delete BACKUP_ID`        | Delete. Refused while artifacts exist                  |
| `sctl backup submit BACKUP_ID FILE`   | Upload to a manual backup                              |

### `backup configure` flags [#backup-configure-flags]

| Flag                     | Value                                                                 | Applies to       |
| ------------------------ | --------------------------------------------------------------------- | ---------------- |
| `--name`                 | string                                                                | All              |
| `--source-type`          | `postgres`, `mysql`, `redis`, `s3`, `web`, `script`, `file`, `folder` | `local`, `cloud` |
| `--worker`               | worker ID                                                             | `local`          |
| `--schedule`             | cron                                                                  | `local`, `cloud` |
| `--source key=value`     | repeatable                                                            | `cloud` only     |
| `--credential key=value` | repeatable                                                            | `cloud` only     |
| `--encryption-key`       | path to an armoured public key                                        | All              |
| `--compression`          | boolean                                                               | All              |
| `--compression-level`    | 1 to 9, or 0 for the default                                          | All              |
| `--keep-last`            | integer                                                               | All. Write-once  |
| `--expire-after`         | duration, e.g. `90d`                                                  | All. Write-once  |
| `--lock-for`             | duration, e.g. `30d`                                                  | All. Write-once  |

## Runs [#runs]

| Command               | Flags                 | Description                |
| --------------------- | --------------------- | -------------------------- |
| `sctl run list`       | `--backup` (required) | Recent runs for one backup |
| `sctl run get RUN_ID` |                       | Full timeline, both phases |

## Artifacts [#artifacts]

| Command                              | Flags            | Description                           |
| ------------------------------------ | ---------------- | ------------------------------------- |
| `sctl artifact list`                 | `--backup`       | All artifacts, or one backup's        |
| `sctl artifact get ARTIFACT_ID`      |                  | Size, checksum, key ID, lock state    |
| `sctl artifact download ARTIFACT_ID` | `--output`, `-o` | Download the stored object as-is      |
| `sctl artifact delete ARTIFACT_ID`   |                  | Delete our copy. Refused while locked |

## Restore [#restore]

| Command                             | Flags                                                                             | Description            |
| ----------------------------------- | --------------------------------------------------------------------------------- | ---------------------- |
| `sctl restore postgres ARTIFACT_ID` | `--database` (required), `--host`, `--port`, `--user`, `--password`, `--ssl-mode` | Replay into a database |
| `sctl restore mysql ARTIFACT_ID`    | as above                                                                          | Replay into a database |
| `sctl restore file ARTIFACT_ID`     | `--path` (required)                                                               | Write to a path        |
| `sctl restore folder ARTIFACT_ID`   | `--path` (required)                                                               | Write to a path        |

`--key` applies to every subcommand. The target is validated before anything is downloaded.

## apply [#apply]

| Command      | Flags                                                | Description                  |
| ------------ | ---------------------------------------------------- | ---------------------------- |
| `sctl apply` | `-f`, `--filename` (repeatable), `-R`, `--recursive` | Reconcile against a manifest |

`-f -` reads stdin. `apply` never deletes.

## Exit codes [#exit-codes]

| Code | Meaning                                                             |
| ---- | ------------------------------------------------------------------- |
| `0`  | Success                                                             |
| `1`  | Any failure, including validation, authorization and network errors |

The error text goes to stderr and names the cause. There are no per-error exit codes today, so
branch on `0` versus non-zero and read the message.

## Common errors [#common-errors]

| Message                        | Cause                                                |
| ------------------------------ | ---------------------------------------------------- |
| `not signed in`                | No token. The hint line says `run sctl login`        |
| `no workspace selected`        | No workspace. In CI, set `SCTL_WORKSPACE_ID`         |
| `invalid backup id`            | You passed a name where an ID is required            |
| `409 retention_immutable`      | Retention is write-once                              |
| `409 artifact_locked`          | Inside its `lock_for` window                         |
| `409 last_artifact`            | The only artifact left for that backup               |
| `422` naming a permission slug | A human-only or worker-only permission on an API key |
| `403` naming a permission      | Valid credential, missing permission                 |

## Output format [#output-format]

Commands print human-readable tables. **That format is not a stable interface**: for anything
you depend on, call the [API](/docs/api) and read JSON.

## Next [#next]

<Cards>
  <Card href="/docs/api" title="API" description="The stable interface underneath all of this." />

  <Card href="/docs/cli/apply" title="apply" description="The declarative path." />
</Cards>
