v0.8.0 — 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.

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.

Health checks

Run `vivo doctor` to verify that required tools are installed, your config and secrets are valid, and all remotes are reachable — before your first backup.

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.9.02026-06-06

Features

  • add add_call/remove_call/move_call_up/down to config_editor
  • add Pane::Calls, TaskEntry.calls, and App.selected_call
  • add s key to set default task in TUI
  • add set_default_task to config_editor
  • expose call_names() accessor on Task
  • expose default_task field on App
  • mark default task with * in task list
  • render Calls section in TUI task detail pane
  • wire Calls pane events (add/delete/reorder, Tab cycle, navigation)

Bug Fixes

  • add confirmation prompt to delete_call_prompt to match Remotes behavior
  • make repo optional when adding a task, supporting calls-only tasks
  • move_call_down propagates task-not-found error instead of silent no-op
  • only update selected_call cursor when move operation succeeds
  • propagate error when default-task node has no value
  • **tui:** size Remotes and Calls sections by content count
v0.8.02026-06-05

Features

  • **backup_config:** add apply_profile_to_yaml and write_profile_to_secrets
  • **backup:** auto-init local restic repo before first backup
  • **config:** add edit_remote
  • **config:** add edit_task with rename and reference updates
  • **doctor:** add check_fuse() and expose run_with_timeout; add ctrlc dep
  • **mount:** add check_repo_accessible and run_preflight
  • **mount:** add mount_point_path and check_mount_point_valid
  • **mount:** add MountEntry, build_entries, normalize_repo_url
  • **mount:** implement run() with picker, preflight, restic mount, cleanup
  • **mount:** wire up vivo mount subcommand to CLI
  • **tui:** add CredentialType enum and detect_url_type
  • **tui:** add edit task/remote prompts, bind e and o keys
  • **tui:** add fields pane with per-field selection and highlight
  • **tui:** add parse_profile_names and list_profiles
  • **tui:** add select_or_create_profile interactive flow
  • **tui:** add suggest_profile_name
  • **tui:** auto-create repo and directory paths when adding or editing tasks
  • **tui:** expose backup fields via public accessors
  • **tui:** extend TaskEntry with task detail fields
  • **tui:** offer restic init on edit-remote and test-remote when repo missing
  • **tui:** offer restic init when adding a remote with no repo
  • **tui:** replace credentials text prompt with profile select
  • **tui:** rewrite right pane as full task detail view

Bug Fixes

  • **backup_config:** use private 0600 temp file for secrets write
  • **config:** align edit_remote error message, add missing backup block test
  • **config:** preserve node ordering in upsert_or_remove_child, repair malformed nodes
  • **doctor:** consistent FUSE label in fail branch; gate PATH test to Linux
  • **mount:** expand env vars in repo URL before preflight and mount
  • **mount:** lazy unmount on exit; hint to close files before Ctrl+C
  • **mount:** print unmount confirmation on exit
  • **mount:** show snapshot browse paths after mounting
  • **remote:** correct restic copy args and set source repo password for S3 sync
  • **tui:** clamp selected_remote index in render to guard against stale state
  • **tui:** classify s3+https as S3, remove println from profile create
  • **tui:** force full repaint after suspend/resume to fix stale screen on prompt return
  • **tui:** ignore e/d in Remotes pane when task has no remotes
  • **tui:** preserve status message and pane focus across reload; validate remote URL
  • **tui:** remove s3+https from detect_url_type (backend unsupported)
  • **tui:** translate rustfs: to s3: before passing URL to restic in test-remote
  • **tui:** treat prompt cancel (Esc/Ctrl-C) as silent no-op instead of error
  • **tui:** trim profile name before duplicate check and save
v0.7.02026-06-04

Features

  • add update_s3_in_secrets, expose backup_remotes and description on Task
  • **cli:** add vivo remote add/list/remove subcommands
  • **cli:** add vivo secrets import-s3 and update CONFIG_TEMPLATE with rustfs example
  • **cli:** add vivo task add/list/remove subcommands
  • **config-editor:** add TaskSpec, RemoteSpec, and add_task
  • **config-editor:** implement add_remote
  • **config-editor:** implement remove_remote and re-export all editor functions
  • **config-editor:** implement remove_task
  • **remote:** add rustfs: URL prefix alias for S3-compatible remotes
  • **tui:** add vivo manage skeleton with stub render and quit key
  • **tui:** implement full event handling — navigate, add, delete, edit in vivo manage
  • **tui:** implement two-pane layout with task list and remote detail

Bug Fixes

  • **tui:** reload app state after editing config in $EDITOR
v0.6.02026-04-24

Features

  • add dot-matrix banner to --help, help, and init commands
v0.5.02026-04-23

Features

  • add B2 credential import with automatic re-auth on backup failure

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.

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 — an alias for S3-compatible storage. Perfect for home labs and private NAS setups. Import credentials once with vivo secrets import-s3.

rustfs:http://nas:9000/bucket
Initialize once restic init --repo 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

Checks prerequisites and scaffolds your config and secrets files.

$ 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. Import S3/RustFS credentials first.

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

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

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.