depcurfew v1.6.1
On this page

Start with Renovate and Dependabot

What the README and the knowledge base say about these tools, on one page.

Five-minute start

  1. npx depcurfew doctor works before init: without depcurfew.json it compares the repository with the policy init would write and shows, as notes in a block of their own, what init and apply would change, for example a package manager that installs new versions without a release-age delay, with the settings apply would write for it. These notes never make it fail.
  2. npx depcurfew init writes depcurfew.json with the default policy below and lists the tools it detected. When the repository already sets a longer release-age delay for one of them, cooldown.minimum keeps the longest one, and init says where it found it.
  3. npx depcurfew explain shows what it detected and what the policy means for each tool.
  4. npx depcurfew apply --dry-run prints the changes as a diff, without writing anything.
  5. npx depcurfew apply writes them. Run it again whenever depcurfew.json changes; a second run with the same policy changes nothing.
  6. npx depcurfew doctor reports configuration that silently does not work and drift from the policy, and exits with 1 when it finds an error or, with the "doctor": { "failOn": "warning" } that init writes, a warning.
  7. Add the GitHub Action so that doctor runs on every push and reports to code scanning.

The default policy:

{
  "$schema": "https://unpkg.com/depcurfew/schema.json",
  "version": 1,
  "cooldown": {
    "minimum": "3d",
    "exclude": [],
    "securityUpdates": "bypass"
  },
  "installScripts": {
    "default": "deny",
    "allow": [],
    "deny": []
  },
  "sources": {
    "git": "deny",
    "remoteTarball": "deny",
    "file": "allow",
    "directory": "allow"
  },
  "targets": "auto",
  "doctor": {
    "failOn": "warning"
  }
}

Update bots

apply gives Renovate and Dependabot the policy's delay, rounded up to their unit and at least as long as the delay of every package manager after rounding, so that they never propose a version the package managers would refuse. It edits only bot configuration files that exist and adds no entries to them.

  • Dependabot gets cooldown in each updates entry of an ecosystem depcurfew configures (npm, bun, deno, pip, uv, composer, bundler), with the policy's exceptions for that registry under exclude (a bundler entry keeps its own, since the policy names no gems), and in the entries of the ecosystems updated by bots only (below). An include list in such a cooldown stays, but it limits the cooldown to the dependencies it names, so apply warns (bot-rule-shortens-delay, with the entry and the line) unless it is "*"; so it does when an entry keeps its own exclude (actions, gems, the ecosystems updated by bots only) and that list matches every dependency ("*"), since Dependabot then waits for none of them. doctor reports both as before (bot-cooldown-mismatch, broad-exclusion).
  • GitHub Actions. When the repository has workflows in .github/workflows and targets is "auto" or names the bot, the actions they run wait as long as the packages. The github-actions entries of Dependabot get the same default-days (GitHub Actions reads no semver-*-days), and their exclude stays as written, because the policy's exceptions name packages, not actions. The delay at the top level of the Renovate configuration covers its github-actions manager too. doctor (bot-cooldown-mismatch) compares the bot's delay for the actions with cooldown.minimum.
  • Cargo, Go modules, Maven, Gradle and NuGet are updated by bots only. Their package managers have no release-age delay that depcurfew configures (the rows "bots only" in Supported tools say what each has), so depcurfew delays their new versions through the bots alone. When depcurfew.json has a cooldown and targets is "auto" or names the bot, the Dependabot entries cargo, gomod, maven, gradle and nuget get the same default-days as the packages, lower semver-*-days are raised to it, and their exclude stays as written, because the policy's exceptions name npm, Python and Composer packages. The delay at the top level of the Renovate configuration covers its cargo, gomod, maven, gradle and nuget managers; packageRules entries for them by manager, category (rust, golang, java, dotnet) or datasource (crate, go, maven, nuget) count as for the package managers, and the preset security:minimumReleaseAgeCrate gives Cargo dependencies 3 days. doctor (bot-cooldown-mismatch) compares the bot's delay for them with cooldown.minimum, and gives one note per ecosystem when the repository has their files but no update bot, since nothing delays their new versions then. depcurfew looks for these files (Cargo.toml, go.mod, pom.xml, settings.gradle, a .csproj…) in the root, in its direct subdirectories that are not hidden, in workspace packages and in the directories listed in projects; depcurfew explain lists what it found under "Updated by bots only". Other dependencies that come in with the bot's update of a lockfile (Cargo.lock, go.sum…) are not held back, because the package manager has no delay of its own to apply to them.
  • What NuGet's minPublishAgeHours covers. From .NET SDK 11.0.100 (NuGet 8.0, Visual Studio 18.12) on, the attribute minPublishAgeHours of a source in nuget.config holds back new versions only where dotnet package add and dotnet package update choose the version themselves; the 10.0 SDKs and earlier ignore it, and depcurfew does not write it. The NuGet documentation says that an explicit version bypasses it, that restore does not check it (for transitive dependencies too), and that with an age set, restore fails with NU1020 for a floating version such as 1.2.*. The Visual Studio Package Manager UI and Package Manager Console, dotnet package list and dotnet package search are not documented as covered (their NuGet issues are open), nor are dotnet tool, dnx and dotnet new install. check, the Claude Code hook and depcurfew mcp do not look NuGet packages up, so depcurfew delays NuGet dependencies only through the bots.
  • Renovate gets the delay at the top level of its configuration and a packageRules entry for the exceptions of each registry, limited to its datasource: matchDatasources: ["npm"] for npm names, ["pypi"] for pypi: names and ["packagist"] for composer: names, so an exception never reaches a crate, a Go module, a gem or an action of the same name. A built-in preset of extends that gives a datasource in use a shorter delay than the policy (config:best-practices and security:minimumReleaseAgeNpm 3 days for npm, security:minimumReleaseAgePypi for pypi, security:minimumReleaseAgeCrate for crate) wins over the top-level value, since a matching rule wins over the top level; apply then writes a rule with that datasource, matchUpdateTypes: ["major", "minor", "patch"] and the policy's delay at the front of packageRules, which Renovate applies after the rules of the presets and before the repository's own rules and the exception rules, and removes it when the preset goes or no longer waits less. The deprecated renovate key of package.json and .renovaterc get it in the snippet. doctor reports a rule of the repository that gives npm, Python or Composer packages of some names a shorter delay than cooldown.minimum, or none, while the policy's exceptions do not exempt them (broad-exclusion, at the line of the rule), and a rule an earlier apply wrote without matchDatasources: ["npm"]. apply and doctor read the other packageRules entries the way Renovate matches them, also by matchManagers and matchCategories: npm covers the packages of npm, pnpm and Yarn, bun and deno those of Bun and Deno, pep621 those of uv and PDM, poetry, pip_requirements and pipenv those of Poetry, pip and Pipenv, composer those of Composer, bundler those of Bundler, and github-actions the actions of the workflows; the categories are js, python, php, ruby and ci. Globs, /regex/, ! and a single string instead of a list work as in Renovate. A rule that shortens the delay of a package manager in use (or of the actions) gives bot-rule-shortens-delay in apply and bot-cooldown-mismatch in doctor, and one that turns it off gives broad-exclusion. For the actions, a rule with matchFileNames that matches every workflow file of the repository (read as Renovate reads it: * within one directory, ** across them, any case, or /regex/) and a rule with matchDepTypes that matches action, the depType Renovate gives an action of a workflow step, count too; one that matches only some workflow files, or only reusable workflows (workflow), leaves the other actions their delay and does not count. A rule with a glob matcher depcurfew cannot read (braces, character classes, ?, or extglobs such as @(a|b) and +(…)) does not count, and doctor gives a note when it may set a shorter delay. depcurfew does not run a /regex/ that a crafted file could make take minutes: one with a quantified group, a backreference, a lookaround, more than one *, + or {n,}, or more than 256 ways to match through ?, {n,m} and | (16 next to a *, + or {n,}), nor the patterns of a file past a fixed amount of matching work. Such a pattern counts as matching where the rule shortens or turns off the delay, so bot-cooldown-mismatch, broad-exclusion and bot-rule-shortens-delay report the rule and name the pattern; where the rule would make the delay longer, it does not count; so does a rule with a matcher depcurfew does not evaluate (matchBaseBranches, matchJsonata, matchRepositories, matchCurrentAge, and matchFileNames or matchDepTypes for the packages of a package manager), unless a package matcher already limits it to some packages. When rules give the update types different delays, doctor reports each one that is shorter, not only the shortest.
  • Numbers in dependabot.yml are read as Dependabot's YAML library, Ruby's Psych, reads them, which follows YAML 1.1: default-days: 010 is 8 days (octal), 1_0 and 1,0 are 10, 1:30 is 5400, and 0o12 is text. doctor compares the number Dependabot reads with the policy and says how it read it ("default-days: 010 in .github/dependabot.yml, which Dependabot reads as 8"), and apply writes the policy's number in place of one Dependabot reads otherwise. Words are read the same way: yes, no, on and off in any case are booleans and ~ and null in any case are null, so apply writes an exception such as yes, off, 1_0 or 2024-01-01 in double quotes (- "yes"), which Dependabot reads as the name, and treats an unquoted - yes in the file as the boolean it is.
  • YAML aliases. Dependabot does not accept YAML aliases (*name) in .github/dependabot.yml (dependabot-core loads the file without them), so doctor does not read a delay or an exception through one: bot-cooldown-mismatch gives a note at the first alias instead of a result, apply writes the cooldown of an entry out in place of an alias and warns that Dependabot reads nothing from the file (bot-config-unreadable), and init notes it, since it does not keep a longer delay from such a file in cooldown.minimum. GitHub Actions workflows may use aliases: doctor and detection read the env maps, jobs and steps of a workflow through them, at most 100 aliases per file.
  • How old an action is comes from git. Renovate takes the commit date of a tag, the tagger date of an annotated tag, or the date of a GitHub release of that version when that is newer, and holds an update without a date; Dependabot takes the date of the GitHub release, then of the tag, then of the commit, and lets an update without a date through. Whoever makes a commit or a tag sets its git date, so the delay protects actions less than packages from a registry, which records when a version was published.

In a repository without package.json

depcurfew is a Node.js program, and a repository without package.json in its root, such as a Rust, .NET, Python, PHP or Ruby project, does not need one to run it.

In GitHub Actions, the GitHub Action needs nothing installed.

Once, by hand, run an exact release with npx:

npx --yes depcurfew@1.5.2 doctor

Name a release that is at least as old as cooldown.minimum of the policy: depcurfew's own Claude Code hook denies a younger one, and so does npm where its min-release-age is set (npx then fails with ETARGET). The example names the newest release that was at least 7 days old when this README was written, usually the one before the newest. Without --yes, npx asks before it downloads a package the project does not have, and without a terminal or in CI it downloads without asking.

Pinned in the repository, keep depcurfew in the tools directory .claude/depcurfew: its own package.json pins depcurfew exactly, its package-lock.json is committed and .claude/depcurfew/node_modules is git-ignored. npm ci installs what that package-lock.json locks, and --prefix runs it in the tools directory, so both commands run from the root of the repository, without cd:

npm ci --ignore-scripts --prefix .claude/depcurfew
node .claude/depcurfew/node_modules/depcurfew/dist/cli.js doctor

doctor reads this copy too: depcurfew-outdated says when the depcurfew that runs is older than it, and the Claude Code hook can run it. To be offered new releases of the pin, you can add a Dependabot npm entry for the directory /.claude/depcurfew; apply gives it the cooldown of the policy like any other npm entry. The tools directory and the Action pin their versions separately, so update both.

Supported tools

ToolRelease-age delayExceptionsInstall-script allow-list (Python: packages built from source; Composer: plugins)Dependency sourcesVerified
RenovateminimumReleaseAge in renovate.json, renovate.jsonc … (duration string), since 35.46.0packageRules: matchPackageNames + minimumReleaseAge: null, since 35.46.0 ❓nonen/a2026-10-28 – 2026-11-03
Dependabotcooldown in .github/dependabot.yml, .github/dependabot.yaml (days), since 2025-07-01cooldown.exclude, since 2025-07-01 ❓nonen/a2026-10-28 – 2026-11-03
Cargo (bots only)registry.global-min-publish-age in .cargo/config.toml, since Cargo 1.100.0 (depcurfew does not write it) ❓; the delay comes from the bots: Dependabot cargo, Renovate cargon/an/an/a2026-11-03
Go modules (bots only)none ❓; the delay comes from the bots: Dependabot gomod, Renovate gomodn/an/an/a2026-11-03
Maven (bots only)none ❓; the delay comes from the bots: Dependabot maven, Renovate mavenn/an/an/a2026-11-03
Gradle (bots only)none ❓; the delay comes from the bots: Dependabot gradle, Renovate gradlen/an/an/a2026-11-03
NuGet (bots only)minPublishAgeHours in nuget.config, since .NET SDK 11.0.100, only for the versions dotnet package add and dotnet package update choose (depcurfew does not write it); the delay comes from the bots: Dependabot nuget, Renovate nugetn/an/an/a2026-11-03 – 2026-11-11

⚠️ official sources disagree (depcurfew takes the safer reading) · ❓ official sources are incomplete. Every value with its source: docs/knowledge.md.

doctor rules for these tools

bot-cooldown-mismatch

error · An update bot waits less than the package manager, or for the actions of workflows and the dependencies of the ecosystems updated by bots only less than the policy, before proposing a new version.

The bot then opens pull requests with versions the package manager would not pick yet: they fail where the manager re-checks the lockfile or bring in younger versions, and security updates that skip the bot delay fail too. A Dependabot cooldown with an include list delays only the dependencies it names; a Renovate packageRules entry can shorten the delay for a registry, manager, category, update type or the files and depType of actions, each is reported, and one with a matcher depcurfew cannot read gets a note. The actions of workflows and the dependencies of Cargo, Go, Maven, Gradle and NuGet must wait cooldown.minimum; without a bot, the latter get a note. An unreadable bot file (JSON5, a YAML alias) gets a note per package manager that waits. With projects, a bot file inside a project gets a note (bots read only the root's), and a project the root's Dependabot configuration leaves out gets a warning. A Dependabot composer entry gets a note: it counts from the release time the author sets.

Fix: Give the bot a delay at least as long as the package manager's, and for the actions of workflows and the ecosystems updated by bots only as long as cooldown.minimum (depcurfew apply does this).

Every rule: doctor rules.

Sources

Every fact behind these tables, with its official source, is in the knowledge base: Renovate, Dependabot.