## Example setup

[`keld/`](./keld/) is example content for `~/.config/keld`. It contains a config and some env files for the systemd stuff. [`systemd/user/`](./systemd/user/) contains that systemd stuff. Backup runs daily, verify runs monthly, both read from the env files to ping healthchecks.io and let you know whether your backups failed. Both also use mise to install/execute runitor (for healthchecks) and keld.

[`config_long.toml`](./keld/config_long.toml) is more exhaustive.

### 1. Copy the configs

```bash
mkdir -p ~/.config/keld/timers
cp -r examples/keld/* ~/.config/keld/
```

### 2. Edit

Open `~/.config/keld/config.toml` and customize it for your backups:

- Define your presets (e.g., `media@hetzner_media`, `docs@b2_docs`)
- Set your repository URLs
- Configure environment variables for authentication
- Set backup sources via `_arguments`

Backup presets can also define shell hooks:

```toml
["media@".backup]
_arguments = ["/home/user/Music/Final"]
_pre_hooks = ["echo preparing media backup"]
_post_hooks = ["echo backup finished with $KELD_RESTIC_STATUS"]
```

`_pre_hooks` run before `restic backup`. If a pre-hook fails, restic is not
started and post-hooks do not run. `_post_hooks` run after restic is attempted,
even when restic fails. Post-hooks receive `KELD_RESTIC_STATUS` and, when restic
started, `KELD_RESTIC_EXIT_CODE`. Use `keld --show-command --preset <preset>
backup` to preview configured hooks without running them.

Keld status names are based on [restic's documented exit
codes](https://restic.readthedocs.io/en/stable/075_scripting.html#exit-codes),
with one extra status for restic start failures:

| Restic exit code | `KELD_RESTIC_STATUS` | Meaning |
| ---------------- | -------------------- | ------- |
| 0                | `success`            | Restic completed successfully. |
| 1                | `fatal`              | Restic failed; see restic output for details. |
| 2                | `runtime_error`      | Go runtime error. |
| 3                | `partial`            | `backup` could not read some source data. |
| 10               | `repository_missing` | Repository does not exist. |
| 11               | `locked`             | Restic failed to lock the repository. |
| 12               | `wrong_password`     | Repository password was wrong. |
| 130              | `interrupted`        | Restic was interrupted. |
| 143              | `terminated`         | Restic was terminated by SIGTERM. |
| other non-zero   | `unknown_failure`    | Unknown restic failure; treat as failed. |
| restic not started | `start_failed`     | Keld could not start the restic process. |

Repeat this to add backups later.

### 3. Set up healthchecks.io (optional)

Create two checks on [healthchecks.io](https://healthchecks.io) for each backup:

- One for the backup job
- One for the verify job

Create env files in `~/.config/keld/timers/`:

```bash
# ~/.config/keld/timers/mybackup@myrepo.env
CHECK_UUID=your-backup-check-uuid-here

# ~/.config/keld/timers/mybackup@myrepo-verify.env
CHECK_UUID=your-verify-check-uuid-here
```

Repeat this to add backups later.

### 4. Install the systemd units

```bash
mkdir -p ~/.config/systemd/user
cp examples/systemd/user/* ~/.config/systemd/user/
```

### 5. Enable and start the timers

For each backup preset you defined (e.g., `media@hetzner_media`):

```bash
# Escape the @ symbol for systemd instance names
systemctl --user enable keld-backup@media@hetzner_media.timer
systemctl --user start keld-backup@media@hetzner_media.timer

systemctl --user enable keld-verify@media@hetzner_media.timer
systemctl --user start keld-verify@media@hetzner_media.timer
```

Repeat this to add backups later.

### 6. Verify everything is working

```bash
# List active timers
systemctl --user list-timers

# Check service status
systemctl --user status keld-backup@media@hetzner_media.service

# Test a dry run
keld --show-command --preset media@hetzner_media backup
```

Repeat this to add backups later.
