---
title: Approvals and automatic runs
description: "Sign approvals ahead of time so a gateway can carry out agreed kinds of change on named machines, including automatic and scheduled runs."
new_in: "2.2"
---

A **signed approval** is a yes given ahead of time: it allows kinds of action
on named [machines](overview.md) until a date, so work can run when nobody is
watching — a nightly check, a rollout across thirty cameras. Without one,
every change waits for a person, one command at a time. This page covers what
an approval allows, what the gateway checks, automatic and scheduled runs,
and the fix-and-retry loop; for one runbook by hand, see
[Runbooks](runbooks.md).

## The rule

Two people decide, separately: **the approver** signs what is allowed, and
**the gateway’s owner** decides whether signed approvals count on that gateway
at all. A change runs under an approval only if both say yes, and nothing
that deletes or powers off ever runs on a production machine from an
approval.

## Runs on its own vs asks first

| Situation | Without a signed approval | With one that covers it |
|---|---|---|
| Reading a machine (logs, status, config) | Asks once per machine per conversation; on an unattended gateway, only if [reads are allowed](../gateways/overview.md#let-an-unattended-gateway-look) | Runs |
| A change on a machine in change mode | Asks, every command | Runs, logged under the approval |
| A change on a machine in observe mode | Refused | Refused: observe stays observe |
| Delete or power on a **production** machine | Asks, plus typing the name | Never runs from an approval |
| A kind above the gateway’s ceiling | Asks | Doesn’t run from the approval |
| An automatic or scheduled run | Dry run only: looks, changes nothing | Runs the steps, with checks |
| Any change on a gateway running `ysra serve` alone | Ysra asks you to sign an approval | Runs |
| Auto mode | Never answers any of this | — |

## What an approval says

An approval allows **kinds of action** on **named machines** until **a
date**: for example, *restart services on the cameras until 1 November*. It
lasts from 5 minutes to 90 days, and is **waiting for your signature**,
**signed**, **withdrawn** or **expired**.

### Kinds of action

| Kind | Covers | For example |
|---|---|---|
| **read** | Looking: logs, status, configuration | `cat`, `journalctl`, `systemctl status` |
| **service** | Starting, stopping, restarting, enabling or disabling a service; stopping processes | `systemctl restart`, `kill`, `supervisorctl` |
| **config** | Changing files and settings | `cp`, `sed`, `tee`, `crontab`, `sysctl` |
| **packages** | Installing or removing software | `apt`, `dnf`, `pip`, `npm` |
| **network** | Firewall and network settings | `iptables`, `ufw`, `ip`, `nmcli` |
| **containers** | Running and managing containers; removing containers or images counts as **delete** | `docker`, `podman`, `kubectl`, `helm` |
| **delete** | Removing or wiping data | `rm`, `shred`, `mkfs`, `dd` |
| **power** | Reboot, shutdown, power off, halt, suspend, hibernate | `reboot`, `shutdown`, `systemctl poweroff` |
| **users** | Accounts and permissions | `useradd`, `passwd`, `chmod`, `chown` |
| **access** | SSH keys and SSH configuration, including `authorized_keys` and `sshd_config` | `ssh-keygen`, `ssh-copy-id` |
| **shell** | Shells, running as another user, writing through redirection, anything the rules don’t recognise | `bash`, `sudo`, `xargs` |

### The choices under “Ysra may”

| Choice | Allows | Never allows |
|---|---|---|
| **Read only** | read | — |
| **Restart services** | read, service | — |
| **Maintenance — no delete, no power** | read, service, config, packages | delete, power |
| **Everything except delete and power** | read, service, config, packages, network, containers, users | delete, power |
| **Only these commands…** | One command per line; `{name}` stands for one plain word, as in `systemctl restart {service}` | — |

“Never” always wins over “allows”. The gateway’s [ceiling](#on-the-gateway)
applies on top.

## Sign an approval { #sign-an-approval }

Signing is in the **desktop app**, with a key that stays in your computer’s
keychain. The terminal can list and withdraw approvals; the web app and the
phone don’t show them.

1. **Settings → Approvals → Make my approval key** (once). The tab shows its
   **Fingerprint** and **Public key**, with **Copy the commands** for the
   gateway’s owner.
2. The gateway’s owner trusts the key; see [On the gateway](#on-the-gateway).
3. In the Machines panel, open **Approvals → New approval…** and fill in
   **Approve changes**:

    | Field | Options |
    |---|---|
    | **On** | **A group**, **These machines**, or **The *n* selected** |
    | **Ysra may** | One of the choices above |
    | **Until** | **1 hour from now**, **8 hours from now**, **1 day from now**, **7 days from now**, or **Custom…** up to 90 days |
    | **Note (optional)** | What it is for |

4. Choose **Prepare the approval**. A card shows **On**, **Commands**,
   **Never**, **Until**, marked *waiting for your signature*. Nothing is
   allowed yet.
5. Choose **Approve with this computer’s key**, then **Approve** in the
   confirmation dialog.

The thread records *You approved: … Changes outside this still need your
OK.*

<!-- media: machines-sign-approval | Signing an approval in the desktop app | Settings → Approvals with a key made; Machines panel → Approvals → New approval…; On: group "cameras", Ysra may: Restart services, Until: 1 day; Prepare the approval; Approve with this computer’s key; confirm dialog; thread line "You approved: …" -->

## On the gateway { #on-the-gateway }

A gateway ignores signed approvals until its owner turns them on.

| Command | What it does |
|---|---|
| `ysra approvers add <public key> --name "Sam's Mac"` | Trusts an approver’s key, after showing its fingerprint and asking |
| `ysra approvers list` | Who is trusted, and the settings |
| `ysra approvers rm <fingerprint or name>` | Stops trusting one |
| `ysra approvers runs on` | Carries out approved changes |
| `ysra approvers runs off` | Back to asking every time (the default) |
| `ysra approvers ceiling read,service,config` | The most this gateway ever allows from an approval |

Compare the fingerprint with the one under **Settings → Approvals** in the
approver’s app before trusting it. The default ceiling is read, service,
config, packages, network, containers and users: it excludes **delete**,
**power**, **access** and **shell**.

### What the gateway checks on every change

A change runs under an approval only if all of these pass, in order:

1. The machine is named in the approval.
2. The machine is in change mode.
3. It is not a delete or power action on a **production** machine.
4. The approval doesn’t deny this kind of action.
5. The gateway’s ceiling allows it.
6. The approval allows it.
7. The approval hasn’t expired.

## What happens when …

### A gateway runs on its own and reaches a change

Nobody is there to approve, so Ysra asks for a signed approval: “I need your
signed approval to go on: … Sign it in the Ysra desktop app.” A card reads
**Approve changes on *machines*: *kinds*** · **until *date***. In the desktop
app choose **Approve with this computer’s key**; elsewhere the card says *Sign
it in the Ysra desktop app, which holds your approval key.* Once signed, the
work goes on.

Ysra can ask for **service**, **config**, **packages**, **network**,
**containers** and **users** — never **delete**, **power**, **access** or
**shell**. Its request lasts 1 hour unless it asks for longer, at most 1 day.

### Nobody signs (approval ignored)

Nothing changes. The thread waits for you; a request Ysra made lapses at its
end time and counts as **expired**. A single change card that nobody answers
counts as declined. A scheduled automatic run without a valid
approval only does its dry run.

### The machine or gateway is offline

| Where | What happens |
|---|---|
| A machine in an automatic run | It ends **Not answering**; the others carry on |
| The gateway, for a scheduled run | The run doesn’t start: “Nightly camera check” was due but didn’t run: The gateway isn’t connected right now. I’ll try again at its next time. |
| The gateway, for a thread | “*gateway* isn’t connected right now. Run `ysra serve` there.” |

### An approval is withdrawn { #withdraw-an-approval }

Withdraw it in the desktop app, or with `/approvals` in the terminal. Runs
stop using it from their next change, and the thread records *Withdrawn: … I no
longer use it.*

## Automatic runs

An automatic run carries out a [runbook](runbooks.md) on one or more machines
without asking at each step, under a signed approval.

| Stage | What happens |
|---|---|
| Dry run, per machine | Starting checks and each step’s check run; nothing changes. A failing machine is **Not ready** |
| Steps, per machine | Each step, then its check, as in any runbook |
| Across machines | Up to 10 machines at a time |
| Early stop | When at least 3 machines, and at least half of those finished so far, failed at the same step: *I stopped early: 3 of 5 machines failed at step 2; I left the rest alone.* Succeeded machines count as finished; skipped ones don’t |

### Outcomes per machine

| Outcome | Meaning |
|---|---|
| **Done** | Every step ran and every check passed |
| **Fixed** | A check failed, Ysra applied a fix from a source it cites, the check passed, and the rest ran |
| **Needs a person** | No fix found, the fix didn’t work, or the approval didn’t cover a step. What Ysra found is in the thread |
| **Not ready** | The dry run didn’t pass; nothing changed |
| **Not answering** | The gateway couldn’t reach the machine |
| **Skipped** | The run stopped before reaching it |

## When a check fails: investigate and fix { #when-a-check-fails-investigate-and-fix }

When a step’s check fails in an automatic run, Ysra investigates **that
machine only**.

| Rule | Value |
|---|---|
| How it looks | Read-only commands; your workspace’s files first |
| When it applies a fix | Only if a source it read says so: the step’s own **If it fails** text, or a passage from your documents |
| Approval for the fix | The same as any other change |
| Attempts per machine | 2, then **Needs a person** |
| Never used | A shell or `sudo` |

The thread names the source: *cam-01 failed at step 1. I looked: … Following
“known-issues.md”, I ran … and the check passes now.* When it can’t fix it,
the line ends *… and needs a person. What I found: …*. Opening the machine
shows **Findings** and what Ysra ran.

### Keep the fix in the runbook { #keep-the-fix-in-the-runbook }

When the fix came from your documents rather than the runbook, Ysra offers to
add it to that step’s **If it fails**. A card shows **If it fails, now** and
the editable **Proposed** text, with **Add to the runbook** or **Not now**.
Adding makes a new version of the runbook: *I added it to step 1’s “If it
fails” in “Camera check” (version 4).*

## Schedules

In the run sheet, set **When** to **On a schedule**.

| Field | Options |
|---|---|
| **Name** | What the schedule is called |
| **On these days at** | Days from Mon to Sun, and a time |
| **Every** *n* **minutes** | At least 15 minutes, at most a month |
| **With the approval** | For an automatic schedule: which signed approval it runs under |

Times are your computer’s; the schedule is kept in UTC. Without a signed
approval, a schedule is a dry run. **Save the schedule** lists it under
**Schedules** with **dry run** or **with your approval**, how often, and
**Next:** or **Paused**.

| Button | What it does |
|---|---|
| **Pause** / **Resume** | Stops and restarts the schedule |
| **Run now** | Starts a run at once; results arrive in the thread |
| **Delete** | Removes the schedule, after **Delete it** |

## Limits

| Limit | Value |
|---|---|
| Approval lifetime | 5 minutes to 90 days |
| An approval Ysra asks for | 1 hour by default, at most 1 day |
| Machines worked on at once | 10 |
| Fix attempts per machine per run | 2 |
| Shortest schedule interval | 15 minutes |

## Related

- [How machines work](overview.md) — approving one change at a time.
- [Runbooks](runbooks.md) — the plan, the dry run, and step-then-check.
- [Machines and gateways](../gateways/overview.md) — the gateway that checks approvals.
