# Manage SLOs with OpenSLO files

> Export SLOs as OpenSLO v1 YAML, keep them in Git and import them back: supported fields, Belvador annotations, dry-run checks and all-or-nothing saves.

[OpenSLO](https://openslo.com) is an open YAML format for SLOs. Belvador exports and imports a subset of **OpenSLO v1**, so you can keep SLO definitions in Git, review changes in pull requests and recreate them in another workspace.

## Export

Open an SLO and choose **Export OpenSLO**. The file looks like this:

```yaml
apiVersion: openslo/v1
kind: SLO
metadata:
  name: checkout-api-availability
  displayName: Checkout API availability
  annotations:
    "belvador.dev/source": uptime
    "belvador.dev/source-ref": "{\"id\":\"<uptime-check-id>\"}"
    "belvador.dev/sli": availability
    "belvador.dev/alert-policy": preset_default
spec:
  budgetingMethod: Timeslices
  timeWindow:
    - duration: 30d
      isRolling: true
  objectives:
    - target: 0.999
```

`metadata.name` is the SLO's identifier in the workspace; importing a file with the same name updates that SLO. The source is chosen by Belvador annotations, because OpenSLO's own metric queries describe metrics systems Belvador does not use.

## Import

Open **SLOs → Import OpenSLO** and choose a file.

1. **Check file** reads every document and lists, per SLO, whether it will be **new** or an **update** — or every problem with its document number and field path. Nothing is saved yet.
2. **Import** saves the whole file in one step. If any SLO is refused — for example a check this workspace does not own, a source that needs **Allow public sources**, or the plan limit — **none** of the file is saved.

A file may be up to 64 KB with up to 50 SLOs. YAML is read safely: custom tags are refused.

An imported SLO is **managed by the file**: its **Edit** button is locked and the page shows **Managed by OpenSLO file**. Change the file and import it again. Pause, mute and delete still work on the SLO page. Importing a file whose `metadata.name` matches an SLO created in Belvador takes that SLO over.

## Supported fields

| Field | Rule |
|---|---|
| `apiVersion` | `openslo/v1` |
| `kind` | `SLO`; `Service` documents in the same file are accepted and ignored |
| `metadata.name` | required; lowercase letters, digits and `-`, up to 63 characters, unique in the file |
| `metadata.displayName` | the SLO name shown in Belvador (up to 120 characters); `metadata.name` when absent |
| `metadata.labels` | accepted, not used |
| `spec.description` | optional |
| `spec.service` | accepted, not used |
| `spec.indicator` | optional inline `ratioMetric`; accepted, not used — the source annotations decide what is counted |
| `spec.timeWindow` | exactly one rolling window: `7d`, `28d` or `30d` |
| `spec.budgetingMethod` | `Timeslices` for uptime checks, `Occurrences` for monitors, heartbeats and spans |
| `spec.objectives` | exactly one, with `target` between 90 % and 99.99 % as a ratio (`0.999`) |

## Belvador annotations

| Annotation | Value |
|---|---|
| `belvador.dev/source` | `uptime`, `monitor`, `heartbeat` or `spans` |
| `belvador.dev/source-ref` | JSON: `{"id":"<check or monitor id>"}`; monitors may add `"environment"`; spans use `{"projectId":7,"service":"api","operation":"GET /api/orders","environment":"production"}` (operation and environment optional) |
| `belvador.dev/sli` | `availability` (default) or `latency` |
| `belvador.dev/latency-threshold-ms` | required with `latency`: 1–60000 |
| `belvador.dev/alert-policy` | `preset_default` (default), `page_only`, `ticket_only` or `off` |
| `belvador.dev/allow-public-sources` | `"true"` to count data sent with a public key |

## What is refused

Belvador never drops a field silently. Anything outside this subset is refused with `OPENSLO_UNSUPPORTED_FIELD` and the field's path — for example `spec.indicatorRef`, several objectives, `isRolling: false`, calendar windows, `thresholdMetric`, and `AlertPolicy`, `AlertCondition` or `SLI` documents. Alerting is set with the `alert-policy` annotation and [alert rules](https://belvador.dev/en/docs/slos/alerts) instead.
