{
  config,
  lib,
  pkgs,
  ...
}:
with lib;
let
  escape = escapeShellArg;
  cfg = config.rbackup;

  start =
    name: plan:
    let
      login-name = "root";
      identity = plan.sshKeyPath;
      ssh = "ssh -i ${escape identity}";
    in
    pkgs.writers.writeBash "backup.${name}" ''
      set -efu
      rsync_src=${escape plan.src}
      rsync_dst=${escape plan.dst}
      echo >&2 "update snapshot current; $rsync_dst <- $rsync_src"

      rsync \
          --rsh=${escape ssh} \
          --append -avz \
          ${optionalString plan.delete "--delete"} \
          "$rsync_src/" \
          "$rsync_dst"
    '';

in
{
  options.rbackup = {
    plans = mkOption {
      default = { };
      type = types.attrsOf (
        types.submodule (
          { config, ... }:
          {
            options = {
              sshKeyPath = mkOption {
                type = types.str;
              };
              src = mkOption {
                type = types.str;
              };
              dst = mkOption {
                type = types.str;
              };
              startAt = mkOption {
                default = "hourly";
                type = with types; nullOr str; # TODO systemd.time(7)'s calendar event
              };
              delete = mkOption {
                type = types.bool;
                default = true;
                description = "delete old files (adds the --delete argument to rsync)";
              };
              timerConfig = mkOption {
                type = with types; attrsOf str;
                default = optionalAttrs (config.startAt != null) {
                  OnCalendar = config.startAt;
                };
              };
            };
          }
        )
      );
    };
  };

  config = {

    systemd.services = mapAttrs' (
      name: plan:
      nameValuePair "rbackup.${name}" {
        path = with pkgs; [
          coreutils
          gnused
          openssh
          rsync
          util-linux
        ];
        restartIfChanged = false;
        serviceConfig = rec {
          ExecStart = start name plan;
          SyslogIdentifier = ExecStart.name;
          Type = "oneshot";
        };
      }
    ) cfg.plans;

    systemd.timers = mapAttrs' (
      name: plan:
      nameValuePair "rbackup.${name}" {
        wantedBy = [ "timers.target" ];
        timerConfig = plan.timerConfig;
      }
    ) cfg.plans;

  };

}