Skip to content

Setup Entries

A setup entry performs a system change that config files alone cannot: enabling a systemd unit, registering a shell completion, installing a git hook. It pairs a check command (does this already hold?) with a run command (make it hold).

Setup entries run during tidydots restore, in the order they appear under entries.

Example

The vicinae launcher ships a systemd user unit. Installing the package and symlinking the config is not enough — the unit must also be enabled:

  - package:
      managers:
        yay: vicinae-bin
    name: vicinae
    entries:
      - targets:
          linux: ~/.config/vicinae
        name: config
        backup: ./Linux/vicinae
        files: [settings.json]

      - name: enable-service
        check:
          linux: systemctl --user is-enabled --quiet vicinae.service
        run:
          linux: systemctl --user enable --now vicinae.service

On restore, tidydots runs the check. If the unit is already enabled the check exits 0 and nothing happens. If it is not, the run command executes, and the check runs a second time to confirm the change actually took effect.

How it works

1. no `run` command for this OS  -> skip
2. `check` exits 0               -> skip, report "Set up"
3. --dry-run                     -> report what would run; never runs it
4. execute `run`                 -> a non-zero exit is an error
5. re-run `check`                -> still failing is an error

Step 5 catches a script that exits 0 without doing its job.

Fields

Field Type Description
name string Required. Identifies the step in output and in the TUI.
check map: OS → command Required. Exit 0 means "already set up".
run map: OS → command Required. Runs only when check fails.
sudo bool Optional. Runs run with elevated privileges. check never uses sudo.

A sub-entry is either a config entry (it has a backup) or a setup entry (it has a run). It cannot be both, and a setup entry cannot declare targets.

Every OS listed under run must also be listed under check, and vice versa. This is enforced at load time.

The OS map is the platform gate

An absent OS key means the step does not apply there. The entry above has no windows: key, so it is skipped entirely on Windows. No when: clause is needed for this — though the application's own when: still gates the whole group.

Commands

Commands run through sh -c on Unix and powershell -Command on Windows, with the configurations repo root as the working directory. That means multi-line commands and repo-relative script paths both work:

      - name: install-hooks
        check:
          linux: test -x /etc/pacman.d/hooks/pkg-backup-aur.hook
        run:
          linux: sh ./Linux/pacman/install-hooks.sh
        sudo: true

The check contract

Check commands must be side-effect free and fast.

They are executed:

  • on every tidydots restore,
  • during --dry-run (this is how dry-run can truthfully report whether the setup would run),
  • and on every TUI state-detection pass.

systemctl --user is-enabled --quiet vicinae.service satisfies both requirements. A check that mutates state, prompts, or takes seconds to return will make tidydots feel broken.

tidydots cannot enforce this — it is a contract you accept when you write a setup entry.

No state is stored

There is no database and no marker file. The check is the state. If you later disable the vicinae unit by hand, the next restore notices and re-enables it.

This is deliberate: a "we already ran this once" record would go stale the moment its effect was undone, and the step would never repair itself.

Security

Setup commands are arbitrary shell commands from your configuration file. Only use configurations you trust.