Configuration¶
Configuration lives in a [tool.curfew] table in pyproject.toml (uv-native).
An optional standalone curfew.toml is deep-merged on top of it (top-level keys,
no [tool.curfew] prefix).
[tool.curfew]
source_roots = ["src"] # applies to the workspace root package
default_deny = false # true => every first-party module must have a rule
known_first_party = [] # escape hatch for code generated outside source roots
ignore_modules = [] # import names never flagged as unresolved
[tool.curfew.modules."rwa_calc.core"]
depends_on = [] # leaf — may import nothing first-party
interface = ["api"] # only rwa_calc.core.api is public
interface_enforced = true # defaults to true when an interface is declared
[tool.curfew.modules."rwa_calc.io"]
depends_on = ["rwa_calc.core", "rwa_calc.types"]
deprecated_on = ["rwa_calc.legacy"] # allowed but reported as a warning (burndown)
[tool.curfew.external]
ignore = ["setuptools"] # never flag as undeclared
ignore_unused = [] # never flag as unused
[tool.curfew.check]
boundaries = true
externals = true
Module patterns¶
A pattern matches a module by prefix, guarded at a dot boundary so
rwa_calc.io never matches rwa_calc.iolib:
| Pattern | Matches |
|---|---|
pkg.core |
pkg.core and everything under it (subtree) |
pkg.core.* |
same as above (explicit subtree sugar) |
pkg.core! |
only pkg.core exactly |
When several rules match, the longest prefix wins (an exact rule beats a subtree rule on a tie).
Boundary semantics¶
- A module that has a rule is default-deny: it may import only its
depends_ontargets plus its own subtree. - A module with no rule is unrestricted — so you can adopt curfew
incrementally. Set
default_deny = trueto require a rule on every first-party module (ungoverned modules may then only import within their own package). - A public interface lists the names a package exposes. Importing a strict
descendant that isn't in the interface — or a
from pkg import namewhose name isn't listed — is a bypass (error). - A deprecated dependency is allowed but reported as a warning, so you can burn it down over time.
A note on curfew dogfooding itself¶
curfew's own pyproject.toml carries a [tool.curfew] block that documents and
enforces its layering: model and errors are leaves; the engine layers build
up; cli is the orchestrator. curfew check runs against curfew in CI.