Skip to content

Repository files navigation

Machine Setup

Tests Builds Crates.io License Changelog

Declarative machine setup — replicate a workstation after a wipe, keep dotfiles and symlinks in sync, or hand a colleague a config that installs deps and clones the right repos.

Real-world example: .dotfiles machine_setup.yaml.

What's New in v2

  • TUI Dashboard: Real-time progress with task list, per-task logs, elapsed times, and a parallel log stream when multiple tasks run. Powered by ratatui. Use --no-tui (or a non-TTY) for CI.
  • Async Engine: Task execution powered by tokio for concurrent I/O (file ops, git, shell commands with streaming output).
  • Task History: Tracks install/update/uninstall timestamps in ~/.machine_setup/history.json. Already-installed tasks are skipped unless --force is used.
  • PowerShell Support: Use powershell as a shell option alongside bash and zsh.
  • Remote Configs: Point directly at a URL instead of a local file — great for bootstrapping a clean machine without cloning first.

See CHANGELOG.md for release-by-release notes.

Install

Quick Install (no dependencies needed)

macOS / Linux:

curl -fsSL https://raw.githubusercontent.com/timopruesse/machine_setup/main/install/install.sh | sh

Windows (PowerShell):

irm https://raw.githubusercontent.com/timopruesse/machine_setup/main/install/install.ps1 | iex

Other methods

Via Homebrew (macOS / Linux):

brew install timopruesse/repo/machine_setup

Via Cargo:

cargo install machine_setup

Manual download: Grab a binary from the release page.

Run

Subcommands

command description example
install install the defined tasks machine_setup install
update update the defined tasks machine_setup update
uninstall uninstall the defined tasks machine_setup uninstall
list list all of the defined tasks machine_setup list
validate validate the config without executing machine_setup validate
completions generate shell completions machine_setup completions zsh

By default, machine_setup looks for ./machine_setup. If that path has no extension, it tries .yaml, then .yml, then .json. Supported formats are YAML and JSON.

Command line parameters

flag value example
-c
--config
path or URL to the config file machine_setup install -c ./config/my_setup.yaml
-t
--task
only run the specified task machine_setup install -t my_task2
-s
--select
select a task to run machine_setup install -s
--with-deps also run transitive depends_on tasks machine_setup update -t leaf --with-deps
-f
--force
force execution (bypass history checks) machine_setup install --force
--no-tui disable TUI; also auto-disabled on non-TTY / CI machine_setup install --no-tui
-h
--help
display help information machine_setup --help
-v
--version
display version information machine_setup --version
-d
--debug
print additional debug information machine_setup install --debug
-l
--level
set a log level (info, warn, error, debug, trace) machine_setup install --level=info

Remote config files

You can pass a URL instead of a local path — the config is fetched and executed directly. GitHub blob URLs are automatically converted to raw URLs.

machine_setup install -c https://github.com/timopruesse/.dotfiles/blob/main/machine_setup.yaml

This is especially useful for setting up a fresh machine without cloning your dotfiles first:

# Install machine_setup
curl -fsSL https://raw.githubusercontent.com/timopruesse/machine_setup/main/install/install.sh | sh

# Run your dotfiles setup directly from GitHub
machine_setup install -c https://github.com/timopruesse/.dotfiles/blob/main/machine_setup.yaml

TUI Dashboard

When running in an interactive terminal, a TUI dashboard is shown with:

  • Task list with status indicators (pending, running, completed, failed, skipped)
  • Per-task scrollable log output (and a tagged parallel stream when multiple tasks run)
  • Progress bar with completion stats and elapsed times
  • Keyboard navigation:
    • j/k or Up/Down — navigate tasks
    • / — filter tasks by name (Enter to apply, Esc to cancel or clear)
    • PgUp/PgDn — scroll logs; Home/End — jump ( End re-enables follow)
    • q or Ctrl+C — cancel and quit; Esc — clear filter, or quit if none

The TUI is automatically disabled in non-interactive environments (piped output, CI). You can also explicitly disable it with --no-tui.

Configure

Tasks can be defined under the tasks root key. Every task can contain an arbitrary number of commands.

key description values default
tasks root key for all of the tasks
default_shell shell that is used when not specified by the command bash, zsh, powershell bash
temp_dir define where temporary files are stored ~/.machine_setup
parallel run all of the tasks in parallel true or false false
num_threads number of threads when run in parallel numeric > 1 physical processor count - 1

Task specific configuration

key description values examples
os only run on the specified os possible values "linux" or ["linux", "macos"]
parallel run all of the commands in parallel (1 thread per command) true or false false
depends_on run these tasks first (install always expands the chain) list of task names ["base"]

On update / uninstall, -t / -s run only the selected tasks unless you pass --with-deps. Interactive uninstall can offer remaining dependencies; uninstall also warns if other tasks still depend on something in the run set.

Minimal example (see also example_config.yaml for a fuller demo used by make run):

default_shell: "zsh"
parallel: true
tasks:
  tools:
    os: ["linux", "macos"]
    commands:
      - run:
          install: "echo 'install tools'"
          update: "echo 'update tools'"
          uninstall: "echo 'remove tools'"
      - symlink:
          src: "./dotfiles/.zshrc"
          target: "~/.zshrc"
          force: true

  repos:
    commands:
      - clone:
          url: "git@github.com:timopruesse/machine_setup.git"
          target: "~/machine_setup"

Extend a configuration

Extensibility is not explicitly built in. However, it's possible to execute tasks from another configuration via the machine_setup command.

Available config commands

copy

This command copies the contents of a directory to another directory.

argument value required example
src source directory/file Y "./src/files" or "./src/test.txt"
target target directory/file Y "/tmp/target" or "/tmp/target/new.txt"
ignore list of files/directories to ignore - ["dist", "package-lock.json"]
sudo run file operations with sudo - true
example
copy:
  src: "./src/files"
  target: "/tmp/target"
  ignore: ["dist", "package-lock.json"]

# Copy to a protected path
copy:
  src: "./etc/wsl.conf"
  target: "/etc/wsl.conf"
  sudo: true

clone

This command clones a git repository to the specified destination.

argument value required example
url URL to a git repository Y "git@github.com:timopruesse/machine_setup.git"
target target directory Y "~/machine_setup"
example
clone:
  url: "git@github.com:timopruesse/machine_setup.git"
  target: "~/machine_setup"

symlink

This command symlinks all the files from the source directory to the target directory.

argument value required example
src source directory/file Y "./src/files" or "./src/test.txt"
target target directory/file Y "/tmp/target" or "/tmp/new.txt"
ignore list of files/directories to ignore - ["dist", "package-lock.json"]
force true/false -
sudo run file operations with sudo - true

If force is set to true, existing files will be removed and replaced by the symlinks.

When src is a directory, intermediate destinations are always real directories. Leftover directory symlinks under target are unwrapped (the link inode is removed and replaced with an empty real directory; the tree the link pointed at is left untouched). This prevents file symlinks from being written through into the source tree.

example
symlink:
  src: "./src/files"
  target: "/tmp/target"
  ignore: ["dist", "package-lock.json"]
  force: true

# Symlink to a protected path
symlink:
  src: "./etc/my.conf"
  target: "/etc/my.conf"
  sudo: true
  force: true

run

This command executes a shell command.

Hint: Avoid the usage of interactive commands when possible.

argument description required default values
env environment variables -
shell shell that is used - "bash" "bash", "zsh", "powershell"

By default, shell commands will only run during install. You can provide mode-specific commands using install, update, and uninstall instead of commands:

argument description required example
commands commands for install only - "sudo apt-get -y install git"
install commands for installing - "sudo apt-get -y install git"
update commands for updating - "sudo apt-get -y upgrade git"
uninstall commands for uninstalling - "sudo apt-get -y uninstall git"

Use either commands (runs on install only) or install/update/uninstall for mode-specific behavior. They are all top-level keys under run.

example
inline_command:
  run:
    commands: "sudo apt-get -y install git"

multiline_command:
  run:
    commands:
      - "sudo apt-get update"
      - "sudo apt-get -y install git"

updatable_command:
  run:
    env:
      SOME_TOKEN: "abc123"
    install: "sudo apt-get -y install git"
    update: "sudo apt-get -y upgrade git"
    uninstall: "sudo apt-get -y uninstall git"

updatable_multiline_command:
  run:
    env:
      SOME_TOKEN: "abc123"
    install:
      - "sudo apt update"
      - "sudo apt-get -y install git"
    update:
      - "sudo apt-get -y upgrade git"
    uninstall:
      - "sudo apt-get -y uninstall git"

machine_setup

With this command it's possible to include other machine_setup configuration files.

argument description required example
config path to the other config file Y "./my_other_config.yaml"
task define a single task that should be run - "my_other_task"
example
machine_setup:
  config: "./my_other_config.yaml"
  task: "my_other_task" # optional

Releases

Packages

Used by

Contributors

Languages