Keeping Python repos from turning into spaghetti.
Fensu means "fence" in Japanese.
Most linters catch bad code inside files. Fensu catches architectural drift: code crossing the wrong boundary, living in the wrong module, or growing into the wrong shape.
As a repository grows, code moves, lessons get forgotten, and the mental map decays. Tests preserve behavior and types preserve interfaces. Fensu makes the repository's architectural expectations executable.
Fensu enforces:
- which layers may import which;
- what each module or role file may contain;
- whether orchestrator functions stay small;
- whether dataflow and mutation are explicit;
- whether names such as
validate_*mean what they claim.
It ships a coherent default architecture rather than a blank rule framework, then lets projects disable, extend, or replace parts deliberately.
Fensu is functional and self-hosting, but remains pre-release.
Installation
pip install fensu
The authoring/API distribution is fensu. It installs the lockstep
fensu-cli binary package, which exclusively owns the fensu command.
Core-only check, init, rule, map, skills, and --version
execution is native. Configured Python custom rules launch one compatible Python
host only for the policy metadata or callbacks they require.
Built-in commands are available only through the native fensu executable;
python -m fensu is retired. Installing fensu-cli from its source
distribution requires Rust 1.95 or newer.
Fensu requires Python 3.12+ and includes a compiled analysis core. Prebuilt
wheels cover Linux (x86_64, aarch64), macOS (Intel, Apple silicon), and Windows
(x86_64). On other platforms, pip builds from source and requires a Rust
toolchain at version 1.95 or newer.
Quick Start
From the directory containing an existing repository's pyproject.toml, detect
the layout, write a validated configuration with the full ruleset enabled, run an
initial check, and install repository-local agent guidance:
fensu init --yes
For an empty repository, provide the package name to scaffold src/ and tests/:
fensu init --yes --name my_package
Pass --no-skills only when automation explicitly requires configuration without
repository-local guidance. Do not call onboarding complete until this succeeds:
fensu skills --check
Then run:
fensu check
To configure manually instead, add a minimal fensu.toml at the repository root:
roots = ["src/my_package"]
tests defaults to ["tests"], tooling is optional, caching is enabled by
default, and every rule family is on by default. Install and verify agent guidance
after writing configuration manually:
fensu skills
fensu skills --check
fensu check
Product roots and tooling receive structural rules; tests receive test-convention and annotation rules.
Default Structure
Product code uses domain, optional subdomain, then role. Every leaf domain or
subdomain owns meaningful behavior through a direct main/ containing at least one
entry module. Branch-domain parents do not need their own main/; their leaf
subdomains do. Tests mirror the code they cover; tooling uses one ownership level
because scripts/ already establishes the outer boundary.
src/my_package/
└── domain/
└── subdomain/
├── main/
│ └── run.py
├── _helpers/
├── classes/
├── models.py
├── types.py
├── constants.py
└── exceptions.py
tests/unit/src/my_package/domain/subdomain/
├── _test_types.py
└── test_run.py
scripts/
├── run_tool.py
└── tool_name/
├── main/
├── _helpers/
└── classes/
Do not create an empty or initializer-only main/ to satisfy the layout. If a
package contains only passive models, types, constants, exceptions, or classes,
move those declarations into the closest domain or subdomain whose main/ behavior
owns and uses them. Fixed role files are siblings of _helpers/, never descendants
such as _helpers/entry/models.py.
Direct scripts/*.py files are thin command adapters. Supporting logic belongs
under scripts/<tool>/<role>/.
Core Commands
fensu init
fensu check
fensu rule FFS131
fensu map run_plan --depth 3
fensu init detects and validates an onboarding configuration, fensu check
enforces the configured architecture, fensu rule explains one rule and its
remediation, and fensu map renders a conservative project call tree. Downstream
mapping is the default; --direction upstream shows proven callers. Mapping
follows project functions and class methods when imports,
annotations, constructors, or return types prove the receiver. Unique protocol
dispatch can resolve to one concrete implementation; ambiguous protocols and
untyped parameters remain visible as unresolved dispatch seams rather than guessed
implementations. Mapping does not require Fensu
configuration or rule adoption.
fensu check stores disposable evaluation results in a repository-local
SQLite database under .fensu/cache/
and reuses them only after validating source, configuration, rule, implementation,
and project-query inputs. Caching is enabled by default; set cache.enabled = false
in configuration or pass --no-cache for an explicit uncached check. --cache
overrides a disabled project preference for one invocation.
Deleting .fensu/cache/ is always safe; ignore that directory rather than the
complete .fensu/ namespace, which is reserved for other Fensu-owned state.
Enforce It, Then See It
Because Fensu enforces the structure, it can also render it. fensu map
produces a deterministic call tree with clickable path:line locations,
class-qualified method names, and explicit protocol seams while marking unresolved
dynamic calls, depth limits, and cycles. Downstream walks follow proven callees;
upstream walks invert those proven edges and omit callers Fensu cannot resolve.
$ fensu map run_map --depth 4
run_map(...) src/fensu/cli/main/map.py:21
├── _parser(...) src/fensu/cli/main/map.py:53
├── resolve_mapping_project(...) src/fensu/mapping/main/resolve_project.py:11
│ └── resolve_mapping_project(...) src/fensu/mapping/_helpers/project.py:15
│ ├── _find_project_root(...) src/fensu/mapping/_helpers/project.py:73
│ ├── _explicit_source(...) src/fensu/mapping/_helpers/project.py:65
│ ├── _optional_config_source(...) src/fensu/mapping/_helpers/project.py:38
│ │ └── find_config_source(...) src/fensu/config/main/find_config.py:12 (depth limit)
│ └── _configured_project(...) src/fensu/mapping/_helpers/project.py:45
│ ├── load_config(...) src/fensu/config/main/load_config.py:15 (depth limit)
│ └── _configured_source(...) src/fensu/mapping/_helpers/project.py:57
└── build_call_map(...) src/fensu/mapping/main/build.py:12
├── provider(...) src/fensu/mapping/main/build.py:24 (unresolved parameter call)
└── render_tree(...) src/fensu/mapping/_helpers/render.py:19
├── _child_lines(...) src/fensu/mapping/_helpers/render.py:41
│ └── _child_lines(...) src/fensu/mapping/_helpers/render.py:41 (cycle)
└── _label(...) src/fensu/mapping/_helpers/render.py:88
The map is useful precisely because it is not guessing. fensu check enforces
layers, roles, and public surfaces first, and fensu map then renders the
structure the code is required to expose.
Philosophy
Fensu is strict by default wherever it can make an honest deterministic claim. Following the rules should remove repeated architectural decisions from everyday work. Deliberate differences belong in selection, configuration, or custom rules, where they remain visible, rather than in scattered inline suppressions.
Unavoidable external calling conventions can use exact symbol-scoped exceptions:
[[rule_exceptions]]
rule = "FFS120"
path = "src/my_package/integrations/_helpers/callbacks.py"
symbols = ["ProgressCollector.update"]
reason = "The external API invokes this callback positionally."
Exceptions accept one exact rule code, repository-relative Python file, and one
or more qualified symbols. Globs, directories, line numbers, path-only entries,
and inline suppression comments are not supported. fensu check rejects stale
exceptions that no longer suppress a fault.
For a justified rule/path intersection that is broader than one exact finding,
keep the rules and project context active with [[rule_ignores]]:
[[rule_ignores]]
rules = ["FFA", "XGENERATED"]
paths = ["src/my_package/generated/**"]
reason = "Generated interfaces are checked by their source schema."
One declaration must match both the finding's rule code and its reported path. Unlike exact exceptions, path-scoped ignores are not stale-checked.
Agent Skills
Generate repository-aware guidance from the active ruleset:
fensu skills
fensu skills --global
The generated skill includes Fensu usage, rule-supported architecture examples,
navigation and work-handoff guidance, and every enabled core and custom rule.
Existing user-authored skill files are preserved unless --force is supplied.
Custom Rules
Custom checks use X... codes and the same RuleContext as core rules. Once
configured, they participate in fensu check, fensu rule, and generated agent
skills. Rules can declare typed RuleOption values, repositories can override them
under [rule_options.<CODE>], and checks read the validated current value through
ctx.option(). Rules can also use ctx.facts, ctx.project, ctx.text, ctx.syntax, and
ctx.relations; these are the same backend-neutral analysis zones used by Fensu's
built-in rules. Project and filesystem reads made through ctx.project are tracked
for cache invalidation. Raw ast.Module access remains available for checks that need
unrestricted Python syntax traversal. Semantic fact contracts and author-facing models
are public Python APIs, while their production extraction has one native Rust owner;
raw AST, syntax, and relation artifacts remain lazy CPython capabilities. Keep
project-owned checks in the canonical
scripts/fensu_policy/rules/ tooling role and load them explicitly:
tooling = ["scripts"]
rule_paths = ["scripts/fensu_policy/rules"]
See the custom-rule guide for the complete API and configuration.
Documentation
The quickstart, architecture model, configuration reference, adoption guide, and CLI reference live at docs.fensu.dev.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
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 fensu-0.10.0.tar.gz.
File metadata
- Download URL: fensu-0.10.0.tar.gz
- Upload date:
- Size: 413.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a3adcf525b6f8b863e8bb20e5dd78c27211b6d7405208db116357cfc66e7f67f
|
|
| MD5 |
b0967c13408c494ef2d005929da57de1
|
|
| BLAKE2b-256 |
e6c45da98f51e471244edcfe2a4f6b6f692d792e3337665883d2884c3a93f05c
|
Provenance
The following attestation bundles were made for fensu-0.10.0.tar.gz:
Publisher:
publish.yml on chio-labs/fensu
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fensu-0.10.0.tar.gz -
Subject digest:
a3adcf525b6f8b863e8bb20e5dd78c27211b6d7405208db116357cfc66e7f67f - Sigstore transparency entry: 2411324539
- Sigstore integration time:
-
Permalink:
chio-labs/fensu@7e1a779e73429d54ceb12c19b83bf7c2a44f0719 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/chio-labs
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@7e1a779e73429d54ceb12c19b83bf7c2a44f0719 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file fensu-0.10.0-cp312-abi3-win_amd64.whl.
File metadata
- Download URL: fensu-0.10.0-cp312-abi3-win_amd64.whl
- Upload date:
- Size: 3.7 MB
- Tags: CPython 3.12+, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
187112ffa85498f6a7caa36996f59a63db8b41d35b9d252c09056922f0acca9b
|
|
| MD5 |
506cc6decb47d59615b6c6caf22267cf
|
|
| BLAKE2b-256 |
2a830eda17b259dbfb93e9be59b6477e5d21825da130cbb2e14a45848481d2cb
|
Provenance
The following attestation bundles were made for fensu-0.10.0-cp312-abi3-win_amd64.whl:
Publisher:
publish.yml on chio-labs/fensu
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fensu-0.10.0-cp312-abi3-win_amd64.whl -
Subject digest:
187112ffa85498f6a7caa36996f59a63db8b41d35b9d252c09056922f0acca9b - Sigstore transparency entry: 2411324628
- Sigstore integration time:
-
Permalink:
chio-labs/fensu@7e1a779e73429d54ceb12c19b83bf7c2a44f0719 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/chio-labs
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@7e1a779e73429d54ceb12c19b83bf7c2a44f0719 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file fensu-0.10.0-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: fensu-0.10.0-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 4.0 MB
- Tags: CPython 3.12+, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b76cc79ae5d459549c3bbd3bd7c0a7ce4f1743aa1c241d01f98401591f3e2515
|
|
| MD5 |
534bf21ad7a9e5923c5f18201b19e1e1
|
|
| BLAKE2b-256 |
a4826842234039b8d6c20c8c2ed49cbeac4b524d3a26abc2ffc7e02220d6dfc7
|
Provenance
The following attestation bundles were made for fensu-0.10.0-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:
Publisher:
publish.yml on chio-labs/fensu
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fensu-0.10.0-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl -
Subject digest:
b76cc79ae5d459549c3bbd3bd7c0a7ce4f1743aa1c241d01f98401591f3e2515 - Sigstore transparency entry: 2411324983
- Sigstore integration time:
-
Permalink:
chio-labs/fensu@7e1a779e73429d54ceb12c19b83bf7c2a44f0719 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/chio-labs
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@7e1a779e73429d54ceb12c19b83bf7c2a44f0719 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file fensu-0.10.0-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: fensu-0.10.0-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 3.9 MB
- Tags: CPython 3.12+, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
77dd0624619bf2a90ec5710748d4d1c32592fe167ced2144bf42c8ffd30fb30f
|
|
| MD5 |
0daa325440931898cb1af310145d5eaa
|
|
| BLAKE2b-256 |
eea18b671dd214f162b3a1f8fe5c46d5c01725d79c59fbb73f524fd6b32d8b30
|
Provenance
The following attestation bundles were made for fensu-0.10.0-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:
Publisher:
publish.yml on chio-labs/fensu
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fensu-0.10.0-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl -
Subject digest:
77dd0624619bf2a90ec5710748d4d1c32592fe167ced2144bf42c8ffd30fb30f - Sigstore transparency entry: 2411324832
- Sigstore integration time:
-
Permalink:
chio-labs/fensu@7e1a779e73429d54ceb12c19b83bf7c2a44f0719 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/chio-labs
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@7e1a779e73429d54ceb12c19b83bf7c2a44f0719 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file fensu-0.10.0-cp312-abi3-macosx_11_0_arm64.whl.
File metadata
- Download URL: fensu-0.10.0-cp312-abi3-macosx_11_0_arm64.whl
- Upload date:
- Size: 3.7 MB
- Tags: CPython 3.12+, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a13d7a1f7fd6485c37d2f8e9c4351e81ab58e5f7e2f28fd9a28191aa05fcf955
|
|
| MD5 |
e123f77a20c31032f1507694b0d362db
|
|
| BLAKE2b-256 |
dd1ffbeca6042e5c8b7014542af53938ca720bf26e673182bbdd5e75927ff01d
|
Provenance
The following attestation bundles were made for fensu-0.10.0-cp312-abi3-macosx_11_0_arm64.whl:
Publisher:
publish.yml on chio-labs/fensu
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fensu-0.10.0-cp312-abi3-macosx_11_0_arm64.whl -
Subject digest:
a13d7a1f7fd6485c37d2f8e9c4351e81ab58e5f7e2f28fd9a28191aa05fcf955 - Sigstore transparency entry: 2411324688
- Sigstore integration time:
-
Permalink:
chio-labs/fensu@7e1a779e73429d54ceb12c19b83bf7c2a44f0719 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/chio-labs
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@7e1a779e73429d54ceb12c19b83bf7c2a44f0719 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file fensu-0.10.0-cp312-abi3-macosx_10_12_x86_64.whl.
File metadata
- Download URL: fensu-0.10.0-cp312-abi3-macosx_10_12_x86_64.whl
- Upload date:
- Size: 3.8 MB
- Tags: CPython 3.12+, macOS 10.12+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3caf52eb57f5d1f41b3d93fdaff63fcc4e9298edc8a9a9b9d0e4cace82d9b85c
|
|
| MD5 |
6cec30cf4bf1c425ea845e0a02c3f02c
|
|
| BLAKE2b-256 |
f63ca90f1f9155cd0ce4b3728f1a4668258c5d2f480d778d92d3944082a5d737
|
Provenance
The following attestation bundles were made for fensu-0.10.0-cp312-abi3-macosx_10_12_x86_64.whl:
Publisher:
publish.yml on chio-labs/fensu
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fensu-0.10.0-cp312-abi3-macosx_10_12_x86_64.whl -
Subject digest:
3caf52eb57f5d1f41b3d93fdaff63fcc4e9298edc8a9a9b9d0e4cace82d9b85c - Sigstore transparency entry: 2411324890
- Sigstore integration time:
-
Permalink:
chio-labs/fensu@7e1a779e73429d54ceb12c19b83bf7c2a44f0719 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/chio-labs
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@7e1a779e73429d54ceb12c19b83bf7c2a44f0719 -
Trigger Event:
workflow_dispatch
-
Statement type: