depcurfew v1.6.1
On this page

Protecting the whole machine

depcurfew apply protects one project. The user-level configuration of each package manager protects every project on the machine that does not set the same settings itself, and also what runs outside a project: npx, uvx, global installs, and a new project before anyone ran apply in it.

depcurfew init --user
depcurfew apply --user --dry-run
depcurfew apply --user
depcurfew doctor --user
  • The user policy is ~/.config/depcurfew/depcurfew.json (in $XDG_CONFIG_HOME/depcurfew/ when that variable is set to an absolute path, in %APPDATA%\depcurfew\ on Windows). It has the same format as a project policy; under targets: "auto" it configures the package managers found in PATH.
  • depcurfew does not run other programs to learn their versions. It reads the version from the files next to the executable in PATH: the package.json of a tool installed from npm (also Yarn installed as @yarnpkg/cli-dist), the .dist-info folder of one installed from PyPI. A Yarn or pnpm shim of Corepack runs, outside a project, the version Corepack's lastKnownGood.json names (in $COREPACK_HOME, else $XDG_CACHE_HOME/node/corepack, else ~/.cache/node/corepack; %LOCALAPPDATA%\node\corepack on Windows), and a yarnPath in ~/.yarnrc.yml that points to a release named yarn-<version>.cjs, as yarn set version names it, gives Yarn's version; doctor --user says where each version came from. When it cannot, it configures for the latest version it knows and says so, except for tools that stop every command on a value their version does not understand (the last column below): for those it writes nothing until you pass the version, for example --for uv@0.13.6. Bun from its official installer (~/.bun/bin/bun, which writes no version file) or from Homebrew has no version depcurfew can read, so it needs --for bun@<version>.
  • init --user keeps a longer release-age delay that the user files of the installed tools already set, as init does in a project: a delay of 7 days in ~/.npmrc makes cooldown.minimum 7d, and init --user says which setting, value, file and line it took. Deno reads the delay in ~/.npmrc in whole days and ignores any other value, so apply --user writes it for Deno in days, rounded up.
  • Poetry and PDM ask the library platformdirs where their user directory is, and on macOS the answer depends on the platformdirs version in the tool's environment (the rows below). depcurfew reads that version from the platformdirs-<version>.dist-info folder next to the tool's own; when it cannot and XDG_CONFIG_HOME or XDG_DATA_HOME would move the file, apply --user writes where the docs say (~/Library/Application Support/...) and warns with the other file (user-file-uncertain), and doctor --user checks both.
  • apply --user writes the files of all tools or none, as apply does in a project: a user file it cannot read or edit (not UTF-8, a symlink, larger than 1 MiB, a file where its directory belongs) is an error that names it, such as ~/.config/pip/pip.conf, with a fix for that problem, and a file that cannot be written puts back the ones already replaced. init --user and apply --user do not create a missing home directory, and when XDG_CONFIG_HOME or %APPDATA% is a relative path, apply --user writes nothing for the tools that may use it, with a warning (pip then reads pip.conf relative to the directory each command runs in). Run as root (sudo with HOME kept), they leave each file they replace to its owner, and give what they create in the home directory to the owner of the home directory. Run so, they write nothing through a symbolic link in the home directory that leads out of it (~/.config/pip pointing at a directory of root, say), since the owner of the home directory could put one there; the error names the link and where it leads. Files under an absolute XDG_CONFIG_HOME or %APPDATA% outside the home directory are written as before.
  • A key apply --user writes into a user file can be overridden by a file the tool reads ahead of it: pnpm 10 reads ~/.npmrc before its rc file. apply --user warns about a different value there (user-setting-overridden) with the line, and doctor --user reports it.
  • A tool's own project settings win over its user file for the same key. Parts of the policy that a tool reads only from project files, such as per-package allow-lists, are not written into the user file; apply --user names them, and depcurfew apply in the project writes them.
  • A user file is edited as apply edits a project file: a setting the policy manages that is set by hand elsewhere in the file is commented out and comes back when the policy stops managing it (YAML files get the policy's value instead). That includes an exception list the policy leaves empty, the command sections of pip.conf such as [install], and the [pip] table of uv.toml. pip takes section names as written, so [Global] and [ global ] are sections it ignores: apply --user writes its block into a real [global] and leaves them as they are, and doctor --user does not read their keys as global ones. Install-script allow-list entries that the policy does not allow are kept and reported; a longer delay that the policy shortens is reported.
  • doctor --user reports a user file that does not match the user policy, values in user files that weaken every project, and environment variables that make a tool read another file, no file or other values, such as a relative XDG_CONFIG_HOME. It reads values as each tool does: a switch that allows every install script is on for every value the tool does not read as off (dangerously-allow-all-builds=1 in ~/.npmrc for pnpm 10), and a merge key (<<: *defaults) counts in pnpm's config.yaml. A pip.conf that has a section twice, or a key twice in one section, is an error, because pip stops on it; from pip 26.3 that includes two spellings of one key, such as only_binary next to only-binary, and apply --user comments out every hand-written spelling of a key it writes. A missing home directory, or a user file it cannot read, is an error rather than a clean report, and an installed tool too old for settings the user policy needs (npm 10 has no release-age delay and no install-script allow-list) is a warning that says what stays unprotected and which version to update to.
  • Tools that record the release-age delay in their lockfile may lock differently on a machine whose user file sets one than on a machine without it; set the same delay in the project with depcurfew apply so that every machine and CI agree.
ToolUser fileSettings apply --user writes (versions that read them there)Needs the exact version
npmLinux, macOS: ~/.npmrc
Windows: %HOME%\.npmrc (when it is an absolute path), else ~\.npmrc
min-release-age (11.10.0+), min-release-age-exclude (11.17.0+), strict-allow-scripts (11.16.0+), allow-scripts (11.16.0+), allow-git (11.10.0+), allow-remote (11.15.0+), allow-file (11.15.0+), allow-directory (11.15.0+)no
pnpmLinux: $XDG_CONFIG_HOME/pnpm/rc, else ~/.config/pnpm/rc
macOS: $XDG_CONFIG_HOME/pnpm/rc, else ~/Library/Preferences/pnpm/rc
Windows: %XDG_CONFIG_HOME%\pnpm\rc, else %LOCALAPPDATA%\pnpm\config\rc, else ~\.config\pnpm\rc
11.0.0+: Linux: $XDG_CONFIG_HOME/pnpm/config.yaml, else ~/.config/pnpm/config.yaml
macOS: $XDG_CONFIG_HOME/pnpm/config.yaml, else ~/Library/Preferences/pnpm/config.yaml
Windows: %XDG_CONFIG_HOME%\pnpm\config.yaml, else %LOCALAPPDATA%\pnpm\config\config.yaml, else ~\.config\pnpm\config.yaml
minimum-release-age (10.16.0–11.0.0), minimum-release-age-exclude (10.16.0–11.0.0), only-built-dependencies (10.0.0–11.0.0), strict-dep-builds (10.3.0–11.0.0), block-exotic-subdeps (10.26.0–11.0.0), minimumReleaseAge (11.0.0+), minimumReleaseAgeExclude (11.0.0+), minimumReleaseAgeStrict (11.0.0+), strictDepBuilds (11.0.7+), blockExoticSubdeps (11.0.0–12.0.0)yes
Yarn (Berry)Linux, macOS, Windows: ~/.yarnrc.ymlnpmMinimalAgeGate (4.10.2+), npmPreapprovedPackages (4.10.0+), enableScripts (4.0.0+), approvedGitRepositories (4.14.0+)yes
BunLinux, macOS, Windows: $XDG_CONFIG_HOME/.bunfig.toml (when it is set, also to an empty value), else ~/.bunfig.toml
1.4.4+: Linux, macOS, Windows: $XDG_CONFIG_HOME/.bunfig.toml (when it is an absolute path), else ~/.bunfig.toml
install.minimumReleaseAge (1.3.0+), install.minimumReleaseAgeExcludes (1.3.0+)yes
Deno1.45.0+: Linux, macOS, Windows: ~/.npmrcmin-release-age (2.8.0+)no
uvLinux, macOS: $XDG_CONFIG_HOME/uv/uv.toml (when it is an absolute path), else ~/.config/uv/uv.toml
Windows: %APPDATA%\uv\uv.toml, else ~\AppData\Roaming\uv\uv.toml
exclude-newer (0.9.17+), exclude-newer-package (0.9.25+), no-build (0.2.12+), no-build-package (0.2.12+), no-binary-package (0.2.12+)yes
pipLinux: $XDG_CONFIG_HOME/pip/pip.conf, else ~/.config/pip/pip.conf
macOS: ~/Library/Application Support/pip/pip.conf (when the folder exists), else ~/.config/pip/pip.conf
Windows: %APPDATA%\pip\pip.ini, else ~\AppData\Roaming\pip\pip.ini
26.2.0+: Linux: $XDG_CONFIG_HOME/pip/pip.conf, else ~/.config/pip/pip.conf
macOS: $XDG_DATA_HOME/pip/pip.conf (when the folder exists), else ~/Library/Application Support/pip/pip.conf (when the folder exists and $XDG_DATA_HOME is not set), else ~/.config/pip/pip.conf
Windows: %APPDATA%\pip\pip.ini, else ~\AppData\Roaming\pip\pip.ini
26.3.0+: Linux: $XDG_CONFIG_HOME/pip/pip.conf (when it is an absolute path), else ~/.config/pip/pip.conf
macOS: $XDG_DATA_HOME/pip/pip.conf (when it is an absolute path and the folder exists), else ~/Library/Application Support/pip/pip.conf (when the folder exists and $XDG_DATA_HOME is not an absolute path), else ~/.config/pip/pip.conf
Windows: %APPDATA%\pip\pip.ini, else ~\AppData\Roaming\pip\pip.ini
uploaded-prior-to (26.1.0+), only-binary (7.1.0+), no-binary (7.1.0+)yes
Poetry2.0.0+: Linux: $XDG_CONFIG_HOME/pypoetry/config.toml, else ~/.config/pypoetry/config.toml
macOS: ~/Library/Application Support/pypoetry/config.toml
Windows: %APPDATA%\pypoetry\config.toml, else ~\AppData\Roaming\pypoetry\config.toml
macOS with platformdirs before 4.6.0: ~/Library/Application Support/pypoetry/config.toml
macOS with platformdirs 4.6.0–4.9.6: $XDG_CONFIG_HOME/pypoetry/config.toml, else $XDG_DATA_HOME/pypoetry/config.toml, else ~/Library/Application Support/pypoetry/config.toml
macOS with platformdirs 4.9.6–4.11.8: $XDG_CONFIG_HOME/pypoetry/config.toml, else ~/Library/Application Support/pypoetry/config.toml
macOS with platformdirs 4.11.8+: $XDG_CONFIG_HOME/pypoetry/config.toml (when it is an absolute path), else ~/Library/Application Support/pypoetry/config.toml
solver.min-release-age (2.4.0+), solver.min-release-age-exclude (2.4.0+), installer.only-binary (2.0.0+), installer.no-binary (1.2.0+)no
PDMLinux: $XDG_CONFIG_HOME/pdm/config.toml, else ~/.config/pdm/config.toml
macOS: ~/Library/Application Support/pdm/config.toml
Windows: ~\AppData\Local\pdm\pdm\config.toml
macOS with platformdirs before 4.6.0: ~/Library/Application Support/pdm/config.toml
macOS with platformdirs 4.6.0–4.9.6: $XDG_CONFIG_HOME/pdm/config.toml, else $XDG_DATA_HOME/pdm/config.toml, else ~/Library/Application Support/pdm/config.toml
macOS with platformdirs 4.9.6–4.11.8: $XDG_CONFIG_HOME/pdm/config.toml, else ~/Library/Application Support/pdm/config.toml
macOS with platformdirs 4.11.8+: $XDG_CONFIG_HOME/pdm/config.toml (when it is an absolute path), else ~/Library/Application Support/pdm/config.toml
strategy.exclude-newer (2.27.0+)yes
Pipenvnonenoneno

doctor --user rules

user-policy-invalid

error · The user policy does not follow the schema or cannot be read.

Without a valid user policy (~/.config/depcurfew/depcurfew.json), doctor --user cannot compare the user-level configuration with it, so only the checks that need no user policy run, as when there is none.

Fix: Fix what the message lists, or write a new user policy with depcurfew init --user --force.

user-config-unreadable

error · A user-level configuration file cannot be read, parsed or edited, or the home directory does not exist, so depcurfew cannot check it.

The package manager may still read the file (or stop on it), and its settings may weaken every project on the machine; doctor --user fails closed and reports an error instead of passing silently. A pip.conf that has a section twice, or a key twice in one section (from pip 26.3 also only_binary next to only-binary), stops pip itself. Without a home directory the user files of most tools cannot be found at all.

Fix: Do what the fix of the finding says: fix invalid syntax, give read permission, replace a symlink apply --user does not write through, make a file smaller than 1 MiB, or set HOME to an existing directory.

user-config-drift

warning · needs depcurfew.json · A user-level configuration file does not match the user policy.

depcurfew apply --user writes the user policy (~/.config/depcurfew/depcurfew.json) into the user-level configuration of each installed tool, which protects every project on the machine that does not set the same settings itself, and npx, uvx and global installs. A file that no longer matches leaves that protection weaker than the policy.

Fix: Run depcurfew apply --user.

user-config-weakens

warning · A user-level configuration file has a value that weakens every project that does not set it itself.

Settings in the user-level configuration apply to every project that does not set the same key, and some apply even then (lists that tools merge across files). A value that turns the release-age delay off, exempts packages or allows install scripts or git dependencies there weakens all of them at once, and so does a file the tool reads ahead of the user file.

Fix: Remove the value from the file, or set it in the policy and run depcurfew apply --user.

user-environment-overrides

warning · An environment variable moves, skips or overrides the user-level configuration or the policy.

Package managers read settings from environment variables before their configuration files, and some variables make them read another file or none. A variable set in a shell profile or a CI runner can switch the protection off without any file showing it.

Fix: Unset the variable, or set it to a value the policy allows.