# Configuration
`cargo-cooldown` uses `cooldown.toml`. Allow rules live in the same file under
the `allow` section.
Create one interactively:
```bash
cargo cooldown init
```
## Minimal File
```toml
[cooldown]
incompatible-publish-age = "deny"
lockfile-baseline = "floor"
[registry]
global-min-publish-age = "14 days"
```
Meaning:
- `[registry].global-min-publish-age`: releases newer than this window are
considered fresh
- `[cooldown].incompatible-publish-age`: what cooldown does when Cargo still
requires fresh versions
- `[cooldown].lockfile-baseline`: whether the initial `Cargo.lock` is used as a
version floor
## Resolution Order
Configuration is loaded in this order:
1. environment variables
2. active member `cooldown.toml`, when exactly one workspace member is targeted
3. workspace root or crate root `cooldown.toml`
4. `$CARGO_HOME/cooldown.toml`
Environment variables always win.
Recommended layout:
- single crate: `<crate-root>/cooldown.toml`
- workspace: `<workspace-root>/cooldown.toml`
- optional workspace override: `<member-dir>/cooldown.toml`
Member overrides apply only to unambiguous member runs, such as:
```bash
cargo cooldown check --package member
cargo cooldown check --manifest-path member/Cargo.toml
```
They do not apply to workspace-wide runs such as `--workspace`,
`--package a --package b`, or `--exclude`.
## Supported Keys
`cooldown.toml` supports:
- `[registry].global-min-publish-age`
- `[registry].min-publish-age`
- `[registries.<name>].min-publish-age`
- `[registries.<name>].index`
- `[cooldown].incompatible-publish-age`
- `[cooldown].fallback-accept`
- `[cooldown].lockfile-baseline`
- `now`
- `ttl_seconds`
- `cache_dir`
- `http_retries`
- `verbose`
- `skip_registries`
- `allow`
Environment variables:
- `CARGO_REGISTRY_GLOBAL_MIN_PUBLISH_AGE`
- `CARGO_REGISTRY_MIN_PUBLISH_AGE`
- `CARGO_REGISTRIES_<name>_MIN_PUBLISH_AGE`
- `COOLDOWN_INCOMPATIBLE_PUBLISH_AGE`
- `COOLDOWN_FALLBACK_ACCEPT`
- `COOLDOWN_LOCKFILE_BASELINE`
- `COOLDOWN_NOW`
- `COOLDOWN_TTL_SECONDS`
- `COOLDOWN_CACHE_DIR`
- `COOLDOWN_HTTP_RETRIES`
- `COOLDOWN_VERBOSE`
- `COOLDOWN_SKIP_REGISTRIES`
Unknown keys and invalid values fail configuration loading.
Set `verbose = true` or `COOLDOWN_VERBOSE=1` for debug logs. Normal output stays
compact and ends with one Cargo-style summary of `Cargo.lock` changes.
## Min Publish Age
The canonical 0.3.1+ policy uses RFC-style duration strings:
```toml
[registry]
global-min-publish-age = "14 days"
```
Durations accept `0` or `N seconds`, `minutes`, `hours`, `days`, `weeks`, or
`months`. In cargo-cooldown, `months` is a fixed 30-day unit.
Per-registry overrides reduce or replace the global policy for a registry:
```toml
[registry]
global-min-publish-age = "14 days"
min-publish-age = "5 days"
[registries.internal]
index = "sparse+https://example.com/index/"
min-publish-age = "0"
```
Effective order:
1. crates.io uses `[registry].min-publish-age`, when present.
2. other registries use `[registries.<name>].min-publish-age`, matched by
`index` first, or by resolving `<name>` through Cargo's existing registry
config.
3. `[registry].global-min-publish-age`.
4. default `0`.
cargo-cooldown does not read `.cargo/config.toml` for policy values. It only
uses Cargo's existing registry configuration to resolve real registry names and
effective indexes.
Environment variables:
```bash
CARGO_REGISTRY_GLOBAL_MIN_PUBLISH_AGE="14 days"
CARGO_REGISTRY_MIN_PUBLISH_AGE="5 days"
CARGO_REGISTRIES_INTERNAL_MIN_PUBLISH_AGE="0"
```
Policy environment overrides stay in cargo-cooldown's namespace:
```bash
COOLDOWN_INCOMPATIBLE_PUBLISH_AGE=fallback
COOLDOWN_FALLBACK_ACCEPT=prompt
```
## Cooldown Policy
`[cooldown].incompatible-publish-age` controls what happens after cooldown
tries to make the dependency graph old enough. This matters because cooldown is
a supply-chain safety guard: it reduces the chance that a normal Cargo command
downloads a crate version that was published very recently and may still be in
the highest-risk window for a supply-chain attack.
Values:
- `deny`: fail and restore the original `Cargo.lock` if any fresh version
still cannot be replaced with an older version accepted by Cargo
- `fallback`: try to cool every eligible registry package, keep the best
`Cargo.lock` that Cargo accepts, and warn about fresh versions that Cargo
still requires
- `allow`: skip cooldown entirely
If `[cooldown].incompatible-publish-age` is omitted, config loading defaults to
`deny`. New files generated by `cargo cooldown init` also default to `deny`.
`[cooldown].fallback-accept` controls the unresolved fresh-version prompt:
- `prompt` (default): ask before keeping fresh versions that Cargo still
requires. The prompt lists each crate, version, registry, and publish date.
- `auto`: do not ask; keep the best `Cargo.lock` that Cargo accepts and warn.
Use `auto` for non-interactive workflows that intentionally accept the
fallback result:
```toml
[cooldown]
fallback-accept = "auto"
```
or:
```bash
COOLDOWN_FALLBACK_ACCEPT=auto cargo cooldown update
```
Example:
```toml
[cooldown]
incompatible-publish-age = "fallback"
```
or:
```bash
COOLDOWN_INCOMPATIBLE_PUBLISH_AGE=fallback cargo cooldown update
```
`fallback` is still protective: it cools every package Cargo can accept
without producing an invalid `Cargo.lock`. It is flexible only at the point where
Cargo's resolver requires a fresh version. In that case, cooldown keeps the best
`Cargo.lock` that Cargo accepts and prints the remaining fresh versions for
review.
It also downgrades release-time metadata failures to warnings; use `deny` if a
registry that cannot prove release ages should fail closed.
Common reasons Cargo may still require a fresh version:
- the current `Cargo.toml` requires a version range whose valid releases are
still inside the cooldown window
- a transitive crate uses an exact dependency on a fresh version
- enabled features or target-specific dependencies activate a newer dependency
path
- several crates must move together, but no older compatible set exists
- `[cooldown].lockfile-baseline = "floor"` protects the pre-run `Cargo.lock`
floor
- an allow rule or skipped registry intentionally exempts the package from
normal cooldown handling
Use `deny` when unresolved fresh downloads should be blocked entirely. This
version does not ask interactively before later Cargo commands download a
resolver-constrained fresh version that was not already present in the initial
`Cargo.lock`; `deny` is the fail-closed choice for that workflow.
## Cargo.lock Baseline
`[cooldown].lockfile-baseline` controls whether cooldown may go below versions
already present in the initial `Cargo.lock`.
Values:
- `floor` (default): use the initial `Cargo.lock` as the minimum version floor
- `ignore`: ignore that floor and allow cooldown below initial `Cargo.lock`
versions
With `cargo cooldown update`, the initial `Cargo.lock` means the real file that
existed before the isolated temp-workspace `cargo update` ran.
Example:
```toml
[cooldown]
lockfile-baseline = "ignore"
```
or:
```bash
COOLDOWN_LOCKFILE_BASELINE=ignore cargo cooldown update
```
Important: `lockfile-baseline = "ignore"` is not a force downgrade setting.
Cooldown still asks Cargo to validate the final graph. If Cargo rejects every
older assignment, the fresh version remains unresolved.
## Policy Combinations
Use this table as the main mental model:
| `lockfile-baseline = "floor"` + `incompatible-publish-age = "deny"` | `cargo cooldown init` default and RFC-aligned fail-closed policy. Keep the pre-run `Cargo.lock` as the floor. Cool only versions added or changed by this run. Fail if any new fresh version remains. |
| `lockfile-baseline = "floor"` + `incompatible-publish-age = "fallback"` | Keep the pre-run `Cargo.lock` as the floor. Cool only versions added or changed by this run. Ask before accepting any remaining fresh version unless `fallback-accept = "auto"` is set. Useful for long min-publish-age windows or benchmark runs. |
| `lockfile-baseline = "ignore"` + `incompatible-publish-age = "deny"` | Try to cool every eligible locked registry package, including packages already in `Cargo.lock`. Fail if any fresh version still cannot be cooled. |
| `lockfile-baseline = "ignore"` + `incompatible-publish-age = "fallback"` | Try to cool every eligible locked registry package, keep the best `Cargo.lock` that Cargo accepts, and warn about the remaining fresh versions. |
Why can a fresh version remain?
- the current `Cargo.toml` requires a fresh version range
- a transitive crate uses an exact dependency
- features or target-specific dependencies activate a newer package
- a group of crates has no older combination that Cargo accepts
- an allow rule or skipped registry exempts the package
- `[cooldown].lockfile-baseline = "floor"` protects the pre-run `Cargo.lock`
floor
## Allow Rules
Allow rules reduce the cooldown window for selected crates.
```toml
[[allow.exact]]
crate = "serde"
version = "1.0.218"
[[allow.package]]
crate = "tokio"
min-publish-age = "1 hour"
[[allow.package]]
crate = "openssl"
min-publish-age = "0"
```
Rules:
- `[[allow.exact]]`: allow one exact `(crate, version)` pair
- `[[allow.package]]`: use a shorter cooldown for one crate name
- `min-publish-age = "0"`: exclude that crate from cooldown
- `[allow.global]`: define a shorter default cooldown for all registry crates
`allow.global` and `allow.package` only reduce the effective cooldown. They do
not increase it above the configured min publish age.
Workspace merge behavior:
- `allow.global`: member value replaces workspace value
- `allow.package`: member entries override workspace entries with the same crate
- `allow.exact`: member and workspace entries are unioned and deduplicated
## `skip_registries`
Skip a registry by logical name or effective URL:
```toml
skip_registries = ["crates-io", "sparse+https://example.com/index/"]
```
Environment variable form:
```bash
COOLDOWN_SKIP_REGISTRIES=crates-io,sparse+https://example.com/index/
```
Skipped registries are not inspected, fetched through fallback HTTP, or
downgraded. Their packages still participate in Cargo's resolver constraints.
## `cargo cooldown init`
Use `cargo cooldown init` from the project root to create `cooldown.toml`
interactively.
- in a crate root, it creates one `cooldown.toml`
- in a workspace root, it can create one shared file plus optional member
override files
- it refuses to overwrite existing `cooldown.toml` files
This is cargo-cooldown's setup wizard. It does not forward to Cargo's
`cargo init`.