Skip to main content

Fensu

Keeping Python repos from turning into spaghetti.

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, and --version execution is native; custom rules, skills, and map launch the active environment's Python interpreter.

python -m fensu is the supported fallback if a binary wheel is unavailable. Installing fensu-cli from its source distribution requires Rust.

Fensu requires Python 3.12+ and includes a compiled analysis core. Prebuilt wheels cover Linux (x86_64, aarch64) and macOS (Intel, Apple silicon); on any other platform, pip builds from source, which requires a Rust toolchain. Release wheels are built for Windows x86_64 as well as the listed Linux and macOS platforms.

Quick Start

Detect the repository layout, choose a starting ruleset, and write a validated configuration:

fensu init

For non-interactive setup, use fensu init --yes. To configure manually instead, add fensu.toml at the repository root:

roots = ["src/my_package"]
tests = ["tests"]
tooling = ["scripts"]

[cache]
enabled = true

Then run:

fensu check

All rule families are enabled by default. 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 downstream call tree. Mapping follows project functions and class methods when imports, annotations, constructors, or return types prove the receiver. Calls through 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 downstream call tree with clickable path:line locations, class-qualified method names, and explicit protocol seams while marking unresolved dynamic calls, depth limits, and cycles.

$ 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.

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 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/rules/ tooling role and load them explicitly:

tooling = ["scripts"]
rule_paths = ["scripts/fensu/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

fensu-0.2.1.tar.gz (499.9 kB view details)

Uploaded Source

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

fensu-0.2.1-cp312-abi3-win_amd64.whl (4.8 MB view details)

Uploaded CPython 3.12+Windows x86-64

fensu-0.2.1-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (5.3 MB view details)

Uploaded CPython 3.12+manylinux: glibc 2.17+ x86-64

fensu-0.2.1-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl (5.2 MB view details)

Uploaded CPython 3.12+manylinux: glibc 2.17+ ARM64

fensu-0.2.1-cp312-abi3-macosx_11_0_arm64.whl (4.8 MB view details)

Uploaded CPython 3.12+macOS 11.0+ ARM64

fensu-0.2.1-cp312-abi3-macosx_10_12_x86_64.whl (5.0 MB view details)

Uploaded CPython 3.12+macOS 10.12+ x86-64

File details

Details for the file fensu-0.2.1.tar.gz.

File metadata

  • Download URL: fensu-0.2.1.tar.gz
  • Upload date:
  • Size: 499.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for fensu-0.2.1.tar.gz
Algorithm Hash digest
SHA256 6b1959eecd252a73a69605f76e4b734f041873585d7fc4eb362303d2962ae192
MD5 2862c6be72a8700cd91f1fcf073be023
BLAKE2b-256 591160b19eaf11b7896228958d864a91dd83240f6c37a7da4d24f3a868e48c78

See more details on using hashes here.

Provenance

The following attestation bundles were made for fensu-0.2.1.tar.gz:

Publisher: publish.yml on chio-labs/fensu

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file fensu-0.2.1-cp312-abi3-win_amd64.whl.

File metadata

  • Download URL: fensu-0.2.1-cp312-abi3-win_amd64.whl
  • Upload date:
  • Size: 4.8 MB
  • Tags: CPython 3.12+, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.14

File hashes

Hashes for fensu-0.2.1-cp312-abi3-win_amd64.whl
Algorithm Hash digest
SHA256 f856827c6100a4676d854e97f71c40a2bf11453690e6c3dd825d7611f7aaa9af
MD5 01c8141630a608daab5fdd7a13011007
BLAKE2b-256 1f2b74d98743f0fa2508d20a7be4a041de2ccda6f041e9ecd2bdc570ebf2ba6c

See more details on using hashes here.

Provenance

The following attestation bundles were made for fensu-0.2.1-cp312-abi3-win_amd64.whl:

Publisher: publish.yml on chio-labs/fensu

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file fensu-0.2.1-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.

File metadata

File hashes

Hashes for fensu-0.2.1-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
Algorithm Hash digest
SHA256 a4874ee6357de6c7cab85dd3e8f7fd4b0874886b37afdaf7857d7ddfb7ac0a83
MD5 668fe06732db3f7ba3b9617979f4bd77
BLAKE2b-256 c7f4dae2287a9754b7da610252e7a54401678b64703e0321f0d1b14165f2d7a2

See more details on using hashes here.

Provenance

The following attestation bundles were made for fensu-0.2.1-cp312-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:

Publisher: publish.yml on chio-labs/fensu

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file fensu-0.2.1-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.

File metadata

File hashes

Hashes for fensu-0.2.1-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
Algorithm Hash digest
SHA256 e991f3ac074f85d8b90bdf64670b521227df042a3cd64c9df7a1283406874214
MD5 1d4c26d30aa8f6c833bd0b038484ccf1
BLAKE2b-256 483b8b696fd195f24293cbd667c3a93b7761efebda91c433fe9d953a8071cc05

See more details on using hashes here.

Provenance

The following attestation bundles were made for fensu-0.2.1-cp312-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:

Publisher: publish.yml on chio-labs/fensu

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file fensu-0.2.1-cp312-abi3-macosx_11_0_arm64.whl.

File metadata

File hashes

Hashes for fensu-0.2.1-cp312-abi3-macosx_11_0_arm64.whl
Algorithm Hash digest
SHA256 fab45cf119a349b27bce0190ffb03546983ba3c7f7d6a4aca4ebfdfc3fa12e19
MD5 ac3b9393f7b363efb69ff5d7c019df0e
BLAKE2b-256 b1c6fa253b8edb4e98a47b179e9010cd9dd248dca823dd4c5287dc3ae3af6935

See more details on using hashes here.

Provenance

The following attestation bundles were made for fensu-0.2.1-cp312-abi3-macosx_11_0_arm64.whl:

Publisher: publish.yml on chio-labs/fensu

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file fensu-0.2.1-cp312-abi3-macosx_10_12_x86_64.whl.

File metadata

File hashes

Hashes for fensu-0.2.1-cp312-abi3-macosx_10_12_x86_64.whl
Algorithm Hash digest
SHA256 391307fa6ee8af508752e51882aa576e56ed8f71ea2c2def26f19915804216e9
MD5 f640bbe3c41c318c9e0ec4737d8e4e27
BLAKE2b-256 e165ea74a2e7ea330cac9fcf6f1ba713fdac94e490303f3950ff1326f958f086

See more details on using hashes here.

Provenance

The following attestation bundles were made for fensu-0.2.1-cp312-abi3-macosx_10_12_x86_64.whl:

Publisher: publish.yml on chio-labs/fensu

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

0.14.0

6 files

0.13.1

6 files

0.13.0

6 files

0.12.0

6 files

0.11.0

6 files

0.10.0

6 files

0.9.4

6 files

0.9.3

6 files

0.9.2

6 files

0.9.1

6 files

0.9.0

6 files

0.8.1

6 files

0.8.0

6 files

0.7.0

6 files

0.6.0

6 files

0.5.2

6 files

0.5.0

6 files

0.4.1

6 files

0.4.0

6 files

0.3.0

6 files

This release

0.2.1 This release

6 files

0.0.1

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page