A sudo wrapper for chezmoi to manage root-owned files across your entire
filesystem.
chezroot is a companion wrapper that extends chezmoi's power to your system-level
files, allowing you to manage files in /etc, /Library/LaunchDaemons, or anywhere
else on your root filesystem with the same chezmoi workflow.
Since chezroot is a wrapper and not a reimplementation, it passes most commands,
flags, and configuration options directly to the underlying chezmoi binary.
This documentation focuses on features, limitations, and design choices that are
specific to chezroot (like the profile system, sudo handling, and unsupported
commands). For all standard chezmoi functionality such as template functions,
editor selection logic, or git integration, refer to the official chezmoi
documentation.
- Features
- Platform Support
- Installation
- Usage
- Configuration
- Profiles
- Passwordless sudo
- Design
- Acknowledgements
- Manage the Entire Filesystem: Manages files anywhere, from files in /etcto/Library/LaunchDaemons.
- Isolated Profiles: Manage multiple, independent configurations (e.g., from different repositories) using the --profile option. Each profile's source, config, state, and cache are stored in separate, dedicated directories, ensuring they never conflict.
- Safe sudoExecution: Intelligently wrapschezmoicommands insudoonly when needed.
- User-Level Actions: Automatically drops privileges for commands like editandcd, so you always edit configuration files as your normal user, not as root.
- Safe by Default: chezroot initautomatically creates a.chezmoiignorefile that ignores everything. You must explicitly un-ignore the files you wish to manage.
- No External Library Dependencies: chezrootis a single binary written in Go with no dependencies other thanchezmoiandsudo.
- Cross-Platform: Works seamlessly on both Linux and macOS.
chezroot is designed exclusively for POSIX-like systems (Linux and macOS) that use
sudo for privilege escalation.
Windows is not a supported platform. The Windows administrative model (UAC, "Run
as Administrator") is fundamentally different from sudo. Thus chezroot is not
compatible with PowerShell or the Windows filesystem.
While chezmoi itself works perfectly on Windows, chezroot cannot be used to wrap
it there.
Installation is handled by a package manager appropriate for your platform.
You can install chezroot from the official Homebrew tap:
brew tap jcouball/tap
brew install chezrootPackages for popular Linux distributions are in progress.
# Package coming soon
yay -S chezroot# PPA coming soon
sudo add-apt-repository ppa:jcouball/ppa
sudo apt update
sudo apt install chezroot# COPR repository coming soon
sudo dnf copr enable jcouball/chezroot
sudo dnf install chezrootThe workflow is nearly identical to chezmoi, with one extra safety step. By
default, you will be operating on the default profile, which is stored in
~/.local/share/chezroot/default.
This creates your source directory at ~/.local/share/chezroot/default.
$ chezroot init
info: Running post-init setup...
info: Creating safe-by-default .chezmoiignore...
info: Creating .chezmoiversion...chezroot is safe by default. It will ignore all files until you explicitly
allow them.
Edit the newly created ignore file at
~/.local/share/chezroot/default/.chezmoiignore.
The file will contain a single * (ignore all). To manage /etc/hosts and all files
under /etc/nginx, you would change it to:
# .chezmoiignore
# 1. Ignore everything by default
*
# 2. Un-ignore the specific files and directories
#    you explicitly want to manage.
!/etc/hosts
!/etc/nginxNow you can use the standard chezmoi workflow.
# Add a file from the root filesystem to your source repo
$ chezroot add /etc/hosts
# Edit the file (this runs $EDITOR as your user, not root)
$ chezroot edit /etc/hosts
# See what changes will be applied
$ chezroot diff
# Apply the changes to your system (this runs with sudo)
$ chezroot -v applychezroot is configured primarily via command-line options and environment
variables.
- 
--profile <name>Specifies the profile to use. This overrides the $CHEZROOT_PROFILEenvironment variable if it is also set.See the "Profiles" section for details. 
- 
--configand--config-formatare not supportedchezmoi's--configand--config-formatoptions are not supported.chezroot's core "Profile" feature works by strictly managing all paths for you. Each profile's configuration is always loaded from its dedicated directory (e.g.,~/.config/chezroot/$PROFILE/) to ensure complete isolation. Allowing an external config file would break this model and create a conflict with the--profileoption.
- 
$CHEZROOT_PROFILEDefault: (unset) Specifies the profile to use if the --profileoption is not provided. This is a convenient way to work with a specific profile for an entire terminal session.If neither the --profileoption nor this variable are set,chezrootwill use the profile namedefault.
By default, chezroot manages a single profile (a self-contained set of
configurations). The default profile is named default and is stored in
~/.local/share/chezroot/default.
The current profile in use is controlled using the --profile option or, as a
convenient default, the $CHEZROOT_PROFILE environment variable. If neither of these
is specified the default profile is used.
This is useful if you want to manage different sets of root file configurations from
different git repositories. For example, you could have one repository for your
system-wide shell settings and a completely different repository for managing nginx
configurations.
Let's set up a new profile called nginx to manage web server files.
- 
Initialize the new profile: This command will use the profile name nginxto create a new source directory at~/.local/share/chezroot/nginxand link it to your new repository.chezroot --profile nginx init https://github.com/user/nginx-configs.git 
- 
Add files to the new profile: All subsequent commands must use the --profile nginxoption to operate on this new instance.chezroot --profile nginx add /etc/nginx/nginx.conf 
- 
Use the default profile: To go back to managing your default files, simply run chezrootwithout the option.chezroot apply This works because each profile maintains its own separate configuration, source directory, and state file, so they do not interfere with each other. 
- 
Using the Environment Variable for Convenience If you are going to work on the nginx profile for a while, you can set the environment variable for your session instead of typing the option repeatedly. The --profileoption will always override this variable if you need to switch temporarily.export CHEZROOT_PROFILE=nginx chezroot add /etc/nginx/sites-available/default # Uses 'nginx' profile chezroot apply # Also uses 'nginx' profile 
chezroot provides a dedicated profile command to list, inspect, and delete your
profiles.
A profile consists of four distinct directory paths:
- Source: $HOME/.local/share/chezroot/$PROFILE/
- Config: $HOME/.config/chezroot/$PROFILE/
- State: $HOME/.local/state/chezroot/$PROFILE/
- Cache: $HOME/.cache/chezroot/cache/$PROFILE/
Lists the names of all discovered profiles. This command scans the chezroot config
and data directories and prints a list of all profile names it finds.
Example:
$ chezroot profile list
default
nginx
webserverDisplays the four filesystem paths associated with one or more profiles. This is a read-only command used to inspect the exact directories that make up a profile.
Example:
$ chezroot profile info default nginx
Profile: default
  Config: /Users/james/.config/chezroot/default
  Source: /Users/james/.local/share/chezroot/default
  State:  /Users/james/.local/state/chezroot/default
  Cache:  /Users/james/.cache/chezroot/cache/default
Profile: nginx
  Config: /Users/james/.config/chezroot/nginx
  Source: /Users/james/.local/share/chezroot/nginx
  State:  /Users/james/.local/state/chezroot/nginx
  Cache:  /Users/james/.cache/chezroot/cache/nginxPermanently delete all data associated with one or more profiles.
This is a destructive operation. It will permanently delete the profile's Source, Config, State, and Cache directories and all their contents from your local disk. It will prompt for confirmation before deleting anything.
Options:
| Flag | Shorthand | Description | 
|---|---|---|
| --force | -f | Skips the confirmation prompt. | 
| --dry-run | -n | Prints the paths that would be deleted without actually deleting them. | 
Example:
$ chezroot profile purge nginx
The following 4 directories and all their contents will be PERMANENTLY DELETED:
  - /Users/james/.config/chezroot/nginx
  - /Users/james/.local/share/chezroot/nginx
  - /Users/james/.local/state/chezroot/nginx
  - /Users/james/.cache/chezroot/cache/nginx
Are you sure? [y/N] y
info: Purged profile 'nginx'.To avoid typing your password for every apply or diff, it is highly recommended
to add a sudoers rule.
Create a new file at /etc/sudoers.d/chezroot (as root) with the following content.
Be sure to replace YOUR_USER and use the correct absolute path to the
chezroot script (which you can find with which chezroot).
# /etc/sudoers.d/chezroot
YOUR_USER ALL=(root) NOPASSWD: /usr/local/bin/chezrootThis rule allows your user to run only the chezroot script as root without a
password.
The chezroot command line tool is a wrapper around chezmoi. It aims to be fully
compatible with chezmoi with a few exceptions.
chezroot implements profiles to allow multiple chezmoi-type sources which can be
shared and can configure specific things within the host operating system. For
example, one source might configure a webserver, another might configure system-wide
shell settings, etc.
The current profile is set at the command line with the --profile option or via the
environment variable $CHEZROOT_PROFILE. If a profile is not specified, The profile
default is used.
Profiles are used to create isolation from each other. Each profile has its own source directory, config file, persistent state file, and cache as follows:
- Source Directory: $HOME/.local/share/chezroot/$PROFILE/
- Config File: $HOME/.config/chezroot/$PROFILE/config.*
- Persistent State File: $HOME/.local/state/chezroot/$PROFILE/state.boltdb
- Cache Directory: $HOME/.cache/chezroot/cache/$PROFILE/
The path to the configuration file passed to chezmoi is determined by the profile
and loaded from $HOME/.config/chezroot/$PROFILE/.
Because chezroot must pass an explicit file path to chezmoi (using the --config
flag internally), it automatically discovers the correct configuration file by
searching that directory for config.toml, config.json, config.yaml, or
config.jsonc.
For this reason, the user cannot specify their own path. Use of the chezmoi command
line options -c, --config, and --config-format are not allowed.
To prevent ambiguity, it is an error to have more than one configuration file in a
single profile directory. If chezroot finds both config.toml and config.yaml,
for example, it will abort and report an error.
The path to the source directory passed to chezmoi is also determined by the
profile. The source directory is $HOME/.local/share/chezroot/PROFILE/.
The user cannot change the path to the source directory. Use of the chezmoi command
line options -S and --source-directory are not allowed. If sourceDir is given
in the configuration file, it is ignored.
The source directory and its contents are assumed to be owned by the user invoking
the chezroot command.
The destination directory path is set to "/".
The user cannot change the destination directory path. Use of the chezmoi command
line options -D and --destination-directory are not allowed. If destDir is
given in the configuration file, it is ignored.
The destination files are assumed to be owned by root.
chezroot is designed to be invoked as a non-root user. Internally, chezroot will
run chezmoi and other commands with sudo as needed.
chezroot explicitly unsets any CHEZMOI_* environment variables in the execution
environment before invoking the underlying chezmoi command. This prevents environment
variables from the user's chezmoi setup from interfering with chezroot.
chezroot then reconstructs the CHEZMOI_* variables for the chezmoi subprocess
by mapping CHEZROOT_* variables in two stages:
- 
Global variables: - Variables prefixed with CHEZROOT_are mapped
- For each CHEZROOT_VAR=value, the correspondingCHEZMOI_VAR=valueis set. (Example:CHEZROOT_VERBOSE=truesetsCHEZMOI_VERBOSE=true).
 
- Variables prefixed with 
- 
Profile-Specific variables: - Variables prefixed with CHEZROOT_PROFILE_${PROFILE}_(where${PROFILE}is the name of the currently active profile) are mapped.
- For each CHEZROOT_PROFILE_${PROFILE}_VAR=value, the correspondingCHEZMOI_VAR=valueis set, overwriting any value set by a global variable. (Example: If the active profile isweb, thenCHEZROOT_PROFILE_WEB_VERBOSE=falsesetsCHEZMOI_VERBOSE=false, taking precedence over anyCHEZROOT_VERBOSEsetting).
 
- Variables prefixed with 
Profile-specific variables always take presedence over global variables.
chezroot does not manipulate the PATH variable when running sudo chezmoi.
Most sudo configurations reset the PATH to a predefined, secure set of directories
(often defined by secure_path in /etc/sudoers). This is a security measure to
prevent users from executing arbitrary commands as root just because those commands
happen to be in their personal PATH.
Users should configure absolute paths for any external commands (diff tools, merge tools, git, password managers, encryption tools, etc.) within their chezroot profile's configuration file if those commands are needed during operations that require sudo.
chezroot invokes the underlying chezmoi command without explicitly changing the
current working directory (CWD) from where chezroot itself was run.
- Command line arguments, including any relative paths (e.g., chezroot add ./file), are passed as-is bychezrootto the underlyingchezmoicommand.
- chezmoiwill interpret these relative paths based on its own CWD at the time of execution.
- Important: When chezrootusessudoto runchezmoi,sudomay change the CWD beforechezmoiexecutes (often to/root). This means relative paths provided on the command line might not resolve as expected in commands requiringsudo(likeadd,apply).
- Therefore, it is strongly recommended to use absolute paths when referring to
files on the command line with chezroot, especially for commands that might run withsudo.
- Similarly, users should be cautious when using relative paths inside run_scripts, as the CWD during their execution (especially undersudo) might not be the directory wherechezrootwas invoked. Using absolute paths or determining paths dynamically within scripts is generally safer.
chezroot manages target files that are owned by root. This means that any chezmoi
command that may read or update target files in the destination directory must be
executed with sudo. This includes commands the evaluate templates which may use
template functions that read the target state (i.e, the stat function).
Commands executed WITH sudo are:
- add, apply, cat, destroy, diff, dump, execute-template, init (only when --applyor--one-shotis used), merge, merge-all, purge, re-add, status, unmanaged, update, verify
Commands executed WITHOUT sudo are:
- cat-config, cd, chattr, completion, data, decrypt, dump-config, edit, edit-config, edit-config-template, encrypt, forget, generate, git, help, ignored, import, license, list, managed, secret, source-path, state, target-path, unmanage
Unsupported commands:
- docker, ssh, upgrade
The following are all expected to be owned by the user who invokes chezroot:
- the source directory and its contents recursively
- the cache directory and its contents recursively
- the persistent state file
Many chezmoi commands must be run with sudo which can leave modified files with
root ownership. To prevent this, chezroot will automatically "fix ownership" of
these files. This means that it will chown all affected files and directories back
to the invoking user after any sudo command completes.
chezroot will automatically fix ownership after running the following commands:
- add, apply, destroy, merge, merge-all, purge, re-add, update
Some commands may need additional special handling. The rest of this section gives those details.
The edit options --apply and --watch are not currently supported. Instead run
chezroot edit ... and then chezroot apply as two separate commands.
These options are unsupported because they create a permission conflict. The edit
action must run as your normal user to access your editor and source files, but the
apply action must run with sudo to write to the root filesystem.
chezroot will pass the option --guess-repo-url=false to chezmoi init. This
option is passed as a safety measure to disable chezmoi's default behavior of
guessing a repository URL (like github.com/user/dotfiles). This ensures you
explicitly provide the full URL for your system-level configuration, rather than
accidentally using your personal dotfiles repository.
chezmoi init will be run with sudo only if the --apply or --one-shot option
is passed. In this case, chezroot will fix ownership after sudo chezmoi init
completes.
If $HOME/.local/share/chezroot/$PROFILE/.chezmoiignore does not exist, chezroot
will create an ignore file that ignores everything. You must explicitly un-ignore the
files you wish to manage. It also ignores the config.
If $HOME/.local/share/chezroot/$PROFILE/.chezmoiversion does not exist, chezroot
will create the file containing the minimal version required for chezroot. If the
file exists, chezroot will ensure the version is compatible with the minimal
version required.