v0.16.2 — now on crates.io

Encrypted backups.
Synced everywhere.

vivo·keep wraps restic to orchestrate backups with multi-remote sync — S3, B2, and more. Credentials stay encrypted at rest with SOPS + age.

$ curl -sSf https://raw.githubusercontent.com/dantuck/vivo/main/install.sh | sh

How it works

One command.
Four phases.

1

Backup

restic snapshots your directories to a local repository

2

Check

repo integrity is verified before any remote sync

3

Forget

old snapshots are pruned by your retention policy

4

Sync

data is pushed to all configured remote backends

Features

Everything restic
was missing.

Credentials encrypted at rest

SOPS + age keeps your remote keys out of plaintext configs. Secrets are decrypted in-memory only at runtime.

Multi-remote sync

Push the same backup to S3, Backblaze B2, MinIO, and more in one run. Add as many remotes as you need.

Step control

Use --start-step to skip already-completed phases. Resume from forget, or run sync-only.

Self-updating

Run `vivo update` to pull the latest release. Background version checks notify you after each run.

Flexible sources

Back up a single directory, or point `files-from` at a list of paths. Add an exclude file to skip what you do not need.

Task chaining

Tasks can call other tasks and run shell commands post-backup. Circular references are detected and skipped.

Dry-run mode

Test your full configuration without writing a single byte. Skips remote sync, forwards --dry-run to restic. Set `dry-run true` on a task to override it per task.

Health checks

Run `vivo doctor` to verify that required tools are installed, your config and secrets are valid, and all remotes are reachable. Run `vivo doctor --fix` to auto-install any missing dependencies, including FUSE for `vivo mount`.

Interactive TUI

Run `vivo manage` to open a full-screen config manager. Add, edit, and delete tasks, remotes, and call chains interactively. Set the default task with a keystroke — no manual KDL editing required.

Browse backups as files

Run `vivo mount` to explore any local or remote backup repo as a FUSE filesystem. Navigate snapshots, find individual files, and restore without touching restic directly.

Changelog

What's new.

v0.16.22026-10-16

Bug Fixes

  • **tui:** keep text and selection readable on dark themes
v0.16.12026-10-16

Bug Fixes

  • **update:** skip releases without a binary for this platform
v0.16.02026-10-16

Features

  • **setup:** guide first-run setup through remotes, credentials and a first backup

Bug Fixes

  • **build:** replace unmaintained knuffel with the kdl crate
v0.15.12026-09-06

Bug Fixes

  • expand leading ~ to $HOME in repo/directory paths
v0.15.02026-07-26

Features

  • **doctor:** auto-install FUSE via doctor --fix and vivo init

Configuration

KDL config.
Human-readable.

Configure backups in a clean KDL file. Set your repo, directories to back up, retention policy, and remote destinations — all in one place.

Secrets are stored separately in a SOPS-encrypted YAML file and injected as environment variables at runtime — never written to disk in plaintext.

Default config path ~/.config/vivo/backup.kdl
Default secrets path ~/.config/vivo/secrets.yaml
backup.kdl
// default task to run
default-task "backup"

tasks {
    task "backup" {
        backup {
            repo "$HOME/.local/share/restic/main"
            directory "$HOME"
            exclude-file "$HOME/.config/vivo/excludes"

            retention {
                daily   7
                weekly  5
                monthly 12
                yearly  2
            }

            remote "s3:https://s3.amazonaws.com/my-bucket" {
                credentials "aws"
            }
            remote "b2:my-bucket:restic/main" {
                credentials "b2"
            }
        }

        command "notify-send 'Backup complete'"
    }
}

Remote Backends

Your data.
Your clouds.

S3-compatible

AWS S3, MinIO, or any S3-compatible endpoint. Uses restic copy for fast, verified transfer. Initialize the remote repo once before first sync — `vivo remote add` and `vivo remote test` offer to do it for you.

s3:https://s3.amazonaws.com/my-bucket
Initialize once restic init --repo s3:https://s3.amazonaws.com/my-bucket

RustFS

Self-hosted S3-compatible object storage via the rustfs: prefix — perfect for home labs and private NAS setups. The bucket is created automatically on first sync, and no remote restic init is needed. Set mc-max-workers and mc-limit-upload per remote to throttle uploads and avoid overwhelming your server.

rustfs:http://nas:9000/bucket

Backblaze B2

Cost-effective cold storage via the b2 CLI. Uses b2 sync with automatic replacement of stale files. Credentials are imported automatically and re-authorized on failure. No remote restic repo initialization needed.

b2:my-bucket:restic/main

Quick Start

Up and running
in five steps.

Initialize vivo

A guided setup: checks prerequisites, creates your age key, sets the restic password, adds and tests an off-site remote, then offers a dry-run and a first backup. Steps 2–4 below are the same pieces, available on their own. Not on a terminal? It writes a static starter config instead.

$ vivo init

Add a backup task

Create a named task with its restic repo and the directory to back up. Or use vivo manage for an interactive TUI.

$ vivo task add --name main --repo ~/.local/share/restic/main --dir ~
$ vivo manage

Add remote destinations

Attach one or more remotes to a task — S3, RustFS, or Backblaze B2. Run vivo remote add with no flags for a guided flow, then test every remote any time.

$ vivo secrets import-s3 --profile rustfs
$ vivo remote add --task main --url "rustfs:http://nas:9000/bucket" --credentials rustfs
$ vivo remote test
$ vivo remote list

Add your secrets

Set your restic password and any additional remote credentials, encrypted with SOPS + age.

$ vivo secrets edit

Run a backup

Dry-run first to verify your setup, then run the real backup.

$ vivo --dry-run
$ vivo

vivo exits non-zero if the backup fails or any remote fails to sync, so schedulers can alert on it.

Scheduling

Run it once.
Schedule it anywhere.

vivo runs once and exits, so any scheduler works. Use the full path to vivo, check with vivo --dry-run first, and make sure restic, sops and your sync tools (mc, b2) are on the job's PATH. vivo exits non-zero on any failure, so your scheduler can alert you.

macOS (launchd)

~/Library/LaunchAgents/dev.vivo.backup.plist
<key>ProgramArguments</key>
<array><string>/usr/local/bin/vivo</string></array>
<key>EnvironmentVariables</key>
<dict><key>PATH</key>
  <string>/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin</string></dict>
<key>StartCalendarInterval</key>
<dict><key>Hour</key><integer>2</integer>
  <key>Minute</key><integer>0</integer></dict>
$ launchctl load ~/Library/LaunchAgents/dev.vivo.backup.plist

Linux (systemd timer)

~/.config/systemd/user/vivo.{service,timer}
# vivo.service
[Service]
Type=oneshot
ExecStart=%h/.local/bin/vivo

# vivo.timer
[Timer]
OnCalendar=daily
Persistent=true
$ systemctl --user enable --now vivo.timer

cron

crontab -e
0 2 * * * PATH=/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin \
  /usr/local/bin/vivo >> $HOME/vivo.log 2>&1

Install

Get vivo.

One-line install

Linux and macOS. Downloads the latest binary from GitHub Releases and verifies the SHA256 checksum.

$ curl -sSf https://raw.githubusercontent.com/dantuck/vivo/main/install.sh | sh

From Cargo

Requires Rust installed. Builds from source and installs to your Cargo bin directory.

$ cargo install vivo

Build from source

Clone from Codeberg or GitHub and build manually.

$ git clone https://codeberg.org/tuck/vivo
cd vivo
cargo build --release
cp target/release/vivo /usr/local/bin/

Already installed? Run vivo update to upgrade to the latest release, or vivo update --dry-run to preview without applying.