38 releases (4 breaking)

Uses new Rust 2024

new 0.5.5 May 2, 2025
0.5.4 Apr 30, 2025
0.4.7 Apr 23, 2025
0.3.3 Apr 17, 2025
0.1.9 Mar 11, 2025

#20 in macOS and iOS APIs

Download history 710/week @ 2025-03-07 541/week @ 2025-03-14 39/week @ 2025-03-21 557/week @ 2025-04-04 508/week @ 2025-04-11 1103/week @ 2025-04-18 707/week @ 2025-04-25

2,875 downloads per month

MIT license

85KB
1.5K SLoC

cutler

Powerful, declarative settings management for your Mac, with speed.

Release Builds Rust Tests

Table of Contents

Overview

cutler simplifies macOS configuration by letting you manage system settings through a single TOML file instead of clicking through System Settings or typing complex defaults commands in the terminal.

Define your settings once, then easily apply, track, and revert changes across your system—think of it as infrastructure-as-code for your Mac.

Check out the Usage section for more details.

Installation

brew install hitblast/tap/cutler

Besides using Homebrew as shown above, you can install the project in a couple of other ways:

  • Using cargo:
cargo install cutler
  • Using mise:
# NOTE: This will compile the binary manually for your system.
mise use -g cargo:cutler

Usage

cutler looks for your configuration in a file named config.toml, checking the following locations in order:

  • $XDG_CONFIG_HOME/cutler/config.toml
  • ~/.config/cutler/config.toml
  • ~/.config/cutler.toml
  • config.toml in the current directory (fallback)

It respects your $XDG_CONFIG_HOME setting, so you don't have to worry about path issues. Just place your config.toml file in one of these locations and you're set.

To easily get started, simply type the following command to generate a prebuilt configuration:

cutler init

Anatomy

Here’s a basic example of a TOML configuration for cutler:

[dock]
tilesize = 46

[menuextra.clock]
FlashDateSeparators = true

For more details on the different defaults domains and available values on macOS, take a look at the Resources section. The TOML above translates into these commands:

defaults write com.apple.dock "tilesize" -int "46"
defaults write com.apple.menuextra.clock "FlashDateSeparators"

You can also configure settings for NSGlobalDomain like this:

[NSGlobalDomain]
ApplePressAndHoldEnabled = true

[NSGlobalDomain.com.apple.mouse]
linear = true

cutler converts the above TOML into:

defaults write NSGlobalDomain "ApplePressAndHoldEnabled" -bool true
defaults write NSGlobalDomain com.apple.mouse.linear -bool true

Defaults and External Commands

cutler also supports running external shell commands the moment it applies the defaults. You can define commands with simple syntax like this:

[external]
  [[external.command]]
  cmd = "echo \"Hello World\""

This translates to running:

echo "Hello World"

For more complex scenarios, you can use a more advanced structure with separate arguments and variables:

# Define reusable variables here:
[external.variables]
common_args = ["Hello", "World"]

[external]
  [[external.command]]
  cmd = "echo"
  # If you reference a variable (for example, $common_args) and it isn't defined
  # in the [external.variables] section, cutler will fall back and try to resolve it
  # from the environment (e.g. $PATH).
  args = ["$common_args", "$PATH"]
  sudo = false

This roughly translates to:

echo Hello World /usr/local/bin:/usr/bin:...

Applying Changes and Status Review

Once your configuration file is ready (including your defaults and external commands), apply your settings by running:

cutler apply

After cutler updates the defaults, it will also:

  1. Execute any external commands defined in the [external] section.
  2. Restart necessary system services on your Mac so that the new settings take effect.
  3. Create a snapshot file named .cutler_snapshot in your home directory. This file records your configuration state and helps with reverting later on.

To verify current settings against your configuration, run:

cutler status

To revert modifications, run:

cutler unapply

Now, when it comes to managing the configuration file itself, there is a config command which has two other subcommands:

# Shows the contents of the configuration file.
cutler config show

# Unapplies and deletes the configuration file.
cutler config delete

You can add --verbose for more detail on what happens behind the scenes. For additional information about all available commands, run:

cutler help

Shell Completions

Here is a small tour on how to setup shell-specific completion scripts for cutler.

Bash completions setup

  1. Make a directory to store Bash-specific completions:
mkdir ~/.bash-completion.d/
  1. Generate the completion script using the following command and pipe the output to a new file:
cutler completion bash > cutler.bash
mv cutler.bash ~/.bash-completion.d/
  1. Finally, source the completion script. The best way would be to simply add it to your .bashrc file:
source ~/.bash_completion.d/cutler.bash > ~/.bashrc

Zsh completions setup

  1. Make sure you have a directory for custom completions:
mkdir -p ~/.zfunc
  1. Then, generate the completion script and move it over:
cutler completion zsh > _cutler
mv _cutler ~/.zfunc/
  1. Then, add to your ~/.zshrc:
fpath=(~/.zfunc $fpath)
autoload -U compinit && compinit
  1. Restart your shell or run:
source ~/.zshrc

For other shells

# Fish
cutler completion fish

# Elvish
cutler completion elvish

# PowerShell
cutler completion powershell

Resources

Finding the ideal set of macOS defaults can be challenging. Visit this website to have a look at some useful ones fast: macOS defaults website

Sample configuration files are preincluded with this repository for you to have a look at and get hold of the tool quickly: see examples

Contributing

This is a personal project aimed at making the task of setting up a Mac more straightforward. Contributions are always welcome! Feel free to help out by creating a pull request or submitting an issue.

If you, as a developer, would like to dive into the nitty-gritty of contributing to cutler, view the CONTRIBUTING.md. I'm still writing it as the project progresses.

License

This project is licensed under the MIT License.

Dependencies

~12–21MB
~390K SLoC