Local-first Python dependency & module-boundary checker. No network, no binaries, zero runtime deps.
Project description
curfew
couvre-feu — "cover the fire". An after-hours rule that keeps things within their bounds. That's exactly what this tool does for your imports.
curfew is a local-first Python dependency & module-boundary checker — an
opinionated, fully-offline alternative to tach.
From a single static import-graph engine it does two jobs:
- Module boundaries — enforce which first-party modules/packages may import which (architecture / dependency-direction enforcement).
- External & workspace validation — for each package, verify every imported
third-party package is declared in that package's
pyproject.toml, flag declared-but-unused dependencies, and detect uv workspace leakage (a member importing a package that only resolves because a sibling member declared it in the shared environment).
It also visualises the dependency graph entirely offline.
Why curfew over tach?
tach is excellent, but its graph either uploads your module structure to a
remote web viewer (tach show --web) or emits GraphViz DOT that needs the
GraphViz binary installed to render. In a locked-down bank/regulatory
environment, neither is acceptable.
curfew is local by construction:
- No network, ever. No telemetry, no remote rendering, no "phone home".
- Zero runtime dependencies.
uv tool install curfewpulls in nothing — the engine and CLI run on the standard library alone. (Colour is an optional[rich]extra.) - No mandatory binaries. The default graph output is Mermaid, which renders in GitHub and MkDocs/Zensical with nothing installed. DOT is offered for those who already have GraphViz, but is never required.
- One tool, both checks. Module boundaries and workspace/dependency validation share one import graph.
Install
uv tool install curfew # zero transitive runtime dependencies
uv tool install "curfew[rich]" # optional colour output
Usage
curfew check # run all configured checks; non-zero exit on any error (CI gate)
curfew check --boundaries # module-boundary check only
curfew check --externals # external/workspace check only
curfew show --mermaid -o graph.md # dependency graph as Mermaid (default)
curfew show --dot -o graph.dot # dependency graph as GraphViz DOT (optional)
curfew report path/to/module.py # dependencies and dependents of a module
curfew init # scaffold a [tool.curfew] config from your current structure
Run curfew inside your workspace venv. Workspace-leakage detection relies on the single shared environment that
uvcreates for a workspace.
Configuration
Config lives in a [tool.curfew] table in pyproject.toml (uv-native), with an
optional standalone curfew.toml override.
[tool.curfew]
source_roots = ["src"]
[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
[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 these as undeclared
A module that has a rule is default-deny (only its depends_on plus its own
subtree are allowed). A module with no rule is unrestricted — so you can adopt
curfew incrementally. Set default_deny = true to require a rule on every
first-party module.
Status
Alpha. Built under the OpenAfterHours org.
License
Apache-2.0. See LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file curfew-0.1.0.tar.gz.
File metadata
- Download URL: curfew-0.1.0.tar.gz
- Upload date:
- Size: 100.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
acb669a8b235225a620bd24e582f1268dc1a24d0a6a272eec3827600208643b7
|
|
| MD5 |
f555403bea77041b17765b1feb073329
|
|
| BLAKE2b-256 |
2601bae23dc184f2f5cbaba1031279fdcfeb73505b9e3d00a3cb3a7527c9d134
|
File details
Details for the file curfew-0.1.0-py3-none-any.whl.
File metadata
- Download URL: curfew-0.1.0-py3-none-any.whl
- Upload date:
- Size: 44.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.14 {"installer":{"name":"uv","version":"0.11.14","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d2190f0919886c6b2f2edb0d51a640dba7863fa64d81256c2dcdb5d1fdef4ca7
|
|
| MD5 |
5d64536a22e6c02d31bf8f804eefc5cf
|
|
| BLAKE2b-256 |
a125c949c6952651b91efb1ac973d74921b4be1c4772736d7dda19244379dec2
|