Skip to main content
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. A repo small enough to fit in one file does not need Fensu. The trouble starts as it grows: code moves, teams change, lessons get forgotten, and the mental map decays. Tests help preserve behavior, but nothing preserves the shape of the repo: what belongs where, which layer owns what, which modules are public surfaces. That consistency usually lives in code review and in people’s heads. Fensu makes it executable:
  • Tests codify behavioral expectations.
  • Types codify interface expectations.
  • Fensu codifies architectural expectations.
A prompt or design doc can describe the intended structure. Only an executable rule can tell you, deterministically and every time, when the repo has drifted from it.

What Fensu checks

Fensu is an architecture linter for Python repos. It analyzes your source and reports faults, the places where the code has broken away from the architecture you declared.

Layers and boundaries

Which modules and packages may import which. Absolute imports only, no star imports, no reaching into a sibling’s internals, no importing from tooling at runtime.

Module roles

What each kind of file may contain and where it may live. models.py holds models, types.py holds types, main/ holds orchestrators, _helpers/ holds phases, classes/ holds one class each.

Function shape

Size caps on orchestrators, explicit dataflow, keyword-only arguments, mutate-only-if-returned, and no hidden control flow buried in comprehensions.

Naming contracts

Names that must mean what they claim. Validators raise or pass, predicates return booleans, queries and conversions return values, and iterator names produce iterators.
It also enforces test-suite conventions (mirrored layout, given-when-then naming, dataclass-backed parametrization) and annotation conventions (annotate every parameter and return, plus non-scalar local bindings) in the scopes where those apply. See Rule families for the full set. Fensu ships a coherent default architecture, not a blank rule language. You adopt it and get a serious starting structure, then disable rules, tune thresholds, or add your own rules deliberately once you know what you are changing. Concretely, the default lays out code as domains built from a small set of roles. A domain holds the roles directly, or splits into named subdomains that do:
That is the shipped default. See the architecture model for the full layout and how to adapt it.

Enforce it, then see it

Because Fensu enforces the structure, it can also render it meaningfully.
  • fensu check stops the repo from losing its shape.
  • fensu map helps you see that shape again, as a deterministic downstream call tree with clickable path:line locations.
A fensu map call tree for run_map, showing resolved project calls with path and line locations, an unresolved parameter call, depth-limit markers, and a cycle marker.

fensu map run_map

The map is useful precisely because it is not guessing at an arbitrary repo. Check enforces layers, roles, and public surfaces first; map then renders the structure the code is required to expose. Useful lineage requires declared structure.

Keeping agents on the rails

Increasingly, the code that drifts is the code an agent wrote. Models are good at local edits but not at preserving architecture over time. They tend to:
  • inline too much and grow functions;
  • smear state across boundaries;
  • add imports through the wrong layer;
  • satisfy the letter of a vague rule while violating its intent.
If you have to remind an agent of the same architectural rule repeatedly, that rule should probably be executable. Fensu’s defaults target exactly these failure modes, and fensu skills closes the loop: it generates agent guidance from your active rules, kept in sync automatically, so the rules your agent follows are the rules your CI enforces.

Battle-tested

Fensu is not a tool built for an imagined problem. Earlier versions of these checks ran unnamed for months, first in workplace codebases and then in sqlbuild, a 100k+ line Python project. Fensu turns that hard-won structure into a reusable default. The default is opinionated; the point is to give you a serious starting structure instead of a blank page, then let you adapt it once you know what you are changing.

Get started

Quickstart

Install Fensu, configure a repo, and read your first faults in a few minutes.

Philosophy

Why Fensu is strict by default, and how deliberate deviation works.

Architecture model

Scopes, roles, and the default module layout Fensu enforces.

Adopting Fensu

Rolling out on a new repo versus an existing one.

Custom rules

Write your own rules in Python with the same context the core rules use.
The PyPI distribution is fensu; the command is fensu. Install with pip install fensu and run fensu. Fensu is functional and self-hosting, but pre-release.