Skip to content

API Reference

RuleContext

The public analysis zones, fault constructors, helpers, and models available to custom rules.

RuleContext is the supported interface between a custom rule and Fensu’s analysis engine. It is passed to every rule check as ctx. Import all public protocols, handles, locations, facts, and dependency models from fensu, never from internal package paths.

def check(*, file: File, ctx: RuleContext) -> list[Fault]: ...
def check(*, project: Project, ctx: RuleContext) -> list[Fault]: ...
def check(*, repository: Repository, ctx: RuleContext) -> list[Fault]: ...

The context groups its surface into current-file facts, project/tree facts, an architecture graph, text and syntax analysis, fault construction, position helpers, and configuration. Legacy Python callbacks may ignore the context and walk their ast.Module directly when they need unrestricted Python AST access.

Backend-neutral semantic facts for the current file, computed once and shared by all rules through a single traversal.

CallReturnsPurpose
annotations()AnnotationFactsMissing parameter, return, local, and variable annotations.
comments()tuple[CommentFact, ...]Source comments in token order.
dataclasses()tuple[DataclassFact, ...]Top-level dataclass declarations and field metadata.
function_conditionals()tuple[FunctionConditionalFact, ...]Conditional control flow grouped by owning function.
functions()FunctionFactsReusable structural function metrics.
function_contracts()tuple[FunctionContractFact, ...]Descriptive name, annotation, yield, and return facts.
hygiene()HygieneFactsSyntax-based hygiene locations.
meaningful_returns(name_patterns=())tuple[MeaningfulReturnFact, ...]The first meaningful return per function; name_patterns filters to matching function names.
module_declarations()ModuleDeclarationFactsTop-level statements and classified declarations.
outer_state_mutations()tuple[OuterStateMutationFact, ...]Direct mutations resolving to outer-scope state.
parameter_mutations()tuple[ParameterMutationFact, ...]First direct mutations of function parameters.
project_calls()ProjectCallFactsDiscarded calls resolvable within the project.
project_functions()tuple[ProjectFunctionFact, ...]Top-level function result contracts.
references()ReferenceFactsImport and attribute-reference facts.
test_functions()tuple[PytestFunctionFact, ...]Syntax metadata for test functions.
test_module()PytestModuleFactsModule-shape metadata for test convention policy.
complex_comprehensions()tuple[SourceLocation, ...]Comprehensions combining generators or nesting another comprehension.
top_level_definition_conditionals()tuple[SourceLocation, ...]Test-policy conditionals owned by top-level definitions.
evaluate_rule_calls()tuple[EvaluateRuleCallFact, ...]Statically recognized public rule-harness calls.

Cross-file and filesystem queries. Every call records its input for cache invalidation, so a result stays reusable only while its answers hold. Pass the file whose result depends on the query as requester, normally ctx.path.

CallReturnsPurpose
analysis(requester, path)Analysis | NoneFull analysis for another project file.
dataclasses(requester, path)tuple[DataclassFact, ...]Dataclass facts for another file.
module_function(requester, module_name, function_name)ProjectFunctionFact | NoneA function contract from a resolvable module.
exists(requester, path)boolWhether a path exists.
is_file(requester, path)boolWhether a path is a file.
is_dir(requester, path)boolWhether a path is a directory.
directory_entries(requester, path)tuple[Path, ...]Direct children of a directory.
glob(requester, path, pattern, recursive=False)tuple[Path, ...]Path matches for a pattern.
python_anchor(requester, path)Path | NoneThe Python ownership anchor for a package directory.
dependencies()tuple[ProjectDependency, ...]All requester-to-path dependencies observed so far.
dependencies_for(requester)tuple[ProjectDependency, ...]Dependencies observed for one requester.

An immutable, deterministic view of the authoritative discovered project. It does not perform arbitrary filesystem discovery. Every query records its exact answer against the active file or project-rule requester.

CallReturnsPurpose
pathstuple[ProjectPath, ...]All discovered files and directories.
filestuple[File, ...]All discovered source identities.
children(path=".")tuple[ProjectPath, ...]Immediate discovered children.
descendants(path=".")tuple[ProjectPath, ...]All discovered descendants.
glob(pattern)tuple[ProjectPath, ...]Discovered paths matching a confined POSIX glob.
files_under(path=".")tuple[File, ...]Discovered files at or beneath a path.
position(path)FilePosition | NoneAnalyzer, scope, module/package, domain, role, and entry-point facts for a file.

ProjectPath rejects absolute paths, parent traversal, Windows path spellings, and unsupported path objects. FilePosition includes path, analyzer, source_kind, scope, scope_root, module, package, domain_parts, role, role_depth, is_entry_module, and is_main_module.

For Python, TypeScript, and Svelte targets, an immutable architecture graph resolved from static imports and authoritative discovered modules. Unresolved imports remain explicit and dynamic imports are not represented. Web graph resolution reuses the native analyzer’s static TypeScript, JavaScript, SvelteKit, and configured alias resolution.

CallReturnsPurpose
nodestuple[ModuleNode, ...]Every discovered graph node.
node(file_or_path)ModuleNode | NoneOne focused module lookup.
imports(node_or_file_or_path)tuple[ImportEdge, ...]Authored imports and their resolution status.
dependencies(node_or_file_or_path)tuple[ModuleNode, ...]Resolved direct targets.
dependents(node_or_file_or_path)tuple[ModuleNode, ...]Resolved direct importers.
cycles()tuple[ImportCycle, ...]Deterministic statically proven cycles.

ImportEdge preserves the AuthoredImport, source location, resolved module name, ImportResolution, and optional target node. Graph identities include analyzer and source-kind ownership so they remain safe as additional analyzers gain graphs.

For Rust targets, a versioned immutable workspace fact view transferred from the native analyzer. It contains no syn or Cargo metadata objects.

CallReturnsPurpose
cratestuple[RustCrateFact, ...]All Cargo workspace package, target and dependency identities.
filestuple[RustFileFacts, ...]All selected Rust file, module, source, item and use facts.
crate(identity)RustCrateFact | NoneOne focused crate lookup by stable workspace identity.
file(file_or_path)RustFileFacts | NoneOne focused file lookup by File or ProjectPath.

RustItemFact uses RustItemKind and RustVisibility, preserves derives and implementation targets, and carries a stable SourceLocation. RustUseFact preserves authored parts, source and target modules, optional target file and crate, and a RustUseResolution of RESOLVED, CRATE, EXTERNAL, or UNRESOLVED. RustFileFacts.parse_error remains explicit when source cannot be parsed.

Each broad or focused call records its answer for subject-aware cache replay. Use a focused file() or crate() lookup when unrelated source or Cargo changes should not invalidate a cached result.

For TypeScript and Svelte targets, a versioned immutable fact view transferred from the native analyzers. It contains no parser-library nodes and does not require Node.

CallReturnsPurpose
filestuple[WebFileFacts, ...]All discovered direct, support, excluded, and generated web source facts.
file(file_or_path)WebFileFacts | NoneOne focused file lookup by File or ProjectPath.

WebFileFacts exposes its analyzer, WebSourceKind, WebSourcePurpose, module, source root, scope, authored source, optional parse error, and immutable imports, functions, classes, models, bindings, calls, resources, re-exports, and export counts. WebImportFact.target is a File only when the native analyzer proves a project-local destination. Use ctx.graph for resolved dependency and dependent queries.

syntax_handles contains stable Fensu-owned WebSyntaxHandle byte ranges for imports, declarations, calls, resources, re-exports, Svelte scripts, and runes. Pass one to WebFileFacts.text(handle) to retrieve its authored text without receiving an analyzer AST.

On Svelte targets, WebFileFacts.svelte is a SvelteFileFacts extension when the file is a component or state module. It records script contexts, recognized top-level runes, component markup, route identity, and state-module identity. TypeScript-only targets do not require this extension.

Broad files and focused file() calls record their exact answers for subject-aware cache replay. Tree and graph calls made during the same invocation record their own query-specific dependencies.

Repository rules use ctx.targets instead of an unqualified target context. all() returns every configured RuleTargetFacts handle in target-name order; named(name) returns one exact handle or None.

Each handle exposes its stable Target identity, target-local tree and graph, and the typed python, rust, or web workspace facts owned by its analyzer. repository_path(file_or_path) and repository_location(location) translate target-local evidence before constructing a repository-relative diagnostic. Wrong-analyzer access and access to an analyzer omitted from the active rule’s analyzers fail closed.

Repository contexts have no current file, source, ctx.project, or unqualified analyzer zones. Their queries use a distinct repository requester for cache replay. See Repository rules for the complete execution and cache model.

Source text, opaque syntax identities, and syntax relationships for the current file.

CallReturnsPurpose
text.sourcestrThe complete source text.
text.line(line_number)strOne source line without its ending.
text.slice(source_range)strThe text covered by an end-exclusive range.
syntax.handles(kind=None)tuple[SyntaxHandle, ...]Syntax handles in traversal order, optionally filtered by kind.
syntax.kind(handle)strThe Fensu syntax kind for a handle.
syntax.range(handle)SourceRangeThe source range for a handle.
relations.parent(handle)SyntaxHandle | NoneThe direct parent handle.
relations.children(handle)tuple[SyntaxHandle, ...]Direct child handles in source order.
relations.ancestors(handle)tuple[SyntaxHandle, ...]Parents from nearest to farthest.

The zone protocols are FactAnalysis, ProjectAnalysis, TextAnalysis, SyntaxAnalysis, and RelationAnalysis, all exported from fensu.

The table above describes the Python analysis zones. Serialized Rust rules use ctx.rust, ctx.project.tree, ctx.source, and stable locations. Serialized web rules use ctx.web, ctx.graph, ctx.project.tree, ctx.source, and WebSyntaxHandle. The generic ctx.syntax and ctx.relations zones are unavailable because parser implementation objects are not part of native-analyzer authoring contracts.

Construct diagnostics through the context so the rule’s code, and optionally its declared message and remediation, are wired automatically. Omitted message and remediation use the rule’s envelope values.

CallPurpose
fault(node, message=None, remediation=None)A Fault with line and column taken from an ast node.
fault_at(location, message=None, remediation=None)A Fault from a SyntaxHandle, SourceLocation, or SourceRange.
fault_for(path, line, column, message=None, remediation=None)A Fault at an explicit location.
path_fault(path=None, message=None, remediation=None)A file-level Fault with no specific line.

During a project-rule invocation there is no current file, source, text, syntax, or file-fact object. path_fault() therefore requires an explicit project-relative path, and fault_for() requires an absolute path confined to the analyzed project. fault_at() accepts a SourceLocation or SourceRange; a bare SyntaxHandle cannot be resolved without a current file analysis.

During a repository-rule invocation, path_fault() accepts a repository-relative path and may omit it to report against the repository subject ".". fault_at() accepts a repository-relative SourceLocation; translate a target-local location with target.repository_location(...) first.

Location facts derived from configured roots and scopes, not hardcoded package names.

CallReturnsPurpose
pathPathThe file being checked.
repo_rootPathThe resolved repository root.
sourcestrThe raw source of the current file.
relative_parts()tuple[str, ...]Path parts relative to the matched scope root.
repo_relative_parts()tuple[str, ...]Path parts relative to the repository root.
module_parts()tuple[str, ...]The file’s importable module parts.
scope()ScopeNameThe discovery scope of the current file.
scope_root()PathThe configured root that owns the current file.
scope_roots(scope)tuple[Path, ...]Ordered configured roots for a scope.
role_of(path=None)str | NoneThe role of a path, or the current file.
in_role(role)boolWhether the current file is within a role.
is_entry_module()boolWhether the file is a main/ entry module.
is_main_module()boolWhether the file is within a main/ package.
domain()str | NoneThe top-level domain, if any.
subdomain()str | NoneThe subdomain, if any.

Convenience operations over the current file’s parsed tree.

CallReturnsPurpose
nodes(node_type)list[ast.AST]Nodes of a type from the shared single-pass index.
call_name(node)str | NoneThe called name of a call node.
base_name(node)str | NoneThe base name of an expression.
top_level_functions(module)tuple[ast.AST, ...]Top-level function definitions.
non_docstring_body(module)list[ast.stmt]Module body without its leading docstring.
distinct_callees(fn)frozenset[str]Distinct callee names within a function.
assigned_locals(fn)frozenset[str]Names assigned as locals within a function.
parameter_names(fn)frozenset[str]A function’s parameter names.
inside_loop(node)boolWhether a node is lexically inside a loop.

Prefer ctx.nodes() over ast.walk(module) for module-wide scans so cooperating rules share Fensu’s single traversal.

CallReturnsPurpose
threshold(name, path=None)intThe value for a Threshold after global, per-role, and path overrides.
contracts()Mapping[str, str]The configured function-name behavior contracts.
test_scopes()tuple[str, ...]The configured test scope names, in declaration order.
option(declaration)declaration-specific typeThe current value of an option declared by the active rule.

Pass the exact RuleOption[T] declaration from the active rule to preserve the static return type. Requests for undeclared or cross-rule options are authoring errors. Values are immutable and already validated before evaluation.

All models below are exported from fensu and returned by the calls above. They are frozen dataclasses; inspect exact fields with your editor’s type information.

Locations and handles

ModelDescribes
SourcePositionA one-based line with zero-based byte column and offset.
SourceRangeAn end-exclusive range within one file.
SourceLocationA file and one-based line with zero-based diagnostic column.
SyntaxHandleA file-qualified opaque reference to one syntax node.
NodeIdAn opaque syntax identity unique within one file.

Function and dataflow facts

ModelDescribes
FunctionFactsFunctions in compatibility and top-level source order.
FunctionMetricFactReusable structural metrics for one function.
FunctionContractFactDescriptive return and generator facts for one function.
FunctionConditionalFactConditional control flow owned by a function.
MeaningfulReturnFactThe first meaningful return owned by a function.
ParameterMutationFactThe first direct mutation of one parameter.
OuterStateMutationFactA mutation resolving to module or enclosing-function state.

Annotation facts

ModelDescribes
AnnotationFactsMissing annotation facts from one traversal.
MissingParameterAnnotationFactA parameter requiring an annotation.
MissingReturnAnnotationFactA function requiring a return annotation.
MissingLocalAnnotationFactA first local binding requiring an annotation.
MissingVariableAnnotationFactAn unannotated module variable or class attribute.

Declaration and reference facts

ModelDescribes
ModuleDeclarationFactsTop-level statements and classified declarations.
ModuleStatementFactOne top-level non-docstring statement.
TypeDeclarationFactOne type-layer declaration and its visibility.
DataclassFactOne dataclass declaration and its field and frozen metadata.
ReferenceFactsImports and ordered reference events.
ImportFactOne import statement and its imported names.
ImportAliasFactOne imported name and its local binding.
AttributeReferenceFactOne attribute reference and its leftmost base.
CommentFactOne source comment and its display position.
NamedCallFactOne call with a statically knowable bare name.
HygieneFactsLocations for syntax-based hygiene policies.

Project and dependency facts

ModelDescribes
ProjectFunctionFactA top-level function and whether its annotation promises a result.
ProjectCallFactsResolvable discarded calls for one module.
DiscardedProjectCallFactOne discarded call resolvable within the project.
ProjectDependencyOne requester-to-path dependency observed by a query.
StaticReferenceFactOne expression resolved to an absolute imported symbol.

Subjects, project tree, and architecture graph

ModelDescribes
FileImmutable identity of one discovered source file.
ProjectImmutable identity of one analyzed project.
RepositoryImmutable identity of one configured multi-target repository.
TargetStable name, analyzer, and repository-relative root for one target.
RuleTargetFactsOne named target’s identity, tree, graph, typed facts, and path translators.
RepositoryTargetFactsDeterministic all() and named() target lookup.
ProjectPathNormalized, confined, project-relative POSIX path.
ProjectTreeDeterministic discovered paths, files, and positions.
FilePositionComplete analyzer-neutral layout position for one file.
ArchitectureGraphResolved static project-import graph.
ModuleNodeDiscovered module identity and ownership.
AuthoredImportImport spelling before project resolution.
ImportEdgeAuthored import plus explicit resolution result.
ImportCycleOne statically proven strongly connected component.

Rust facts

ModelDescribes
RustWorkspaceFactsVersioned workspace crates and selected Rust files.
RustCrateFactCargo package identity, manifest, library, targets and dependencies.
RustTargetFactStable Cargo target identity, kinds, source root and entry path.
RustDependencyFactCargo package/source name, dependency kinds and optional local crate.
RustFileFactsSource, module identity, parse result, items and authored uses.
RustItemFactFunction, struct, enum, trait, implementation or module declaration.
RustUseFactAuthored use path and explicit resolution evidence.

Python repository facts

ModelDescribes
PythonWorkspaceFactsVersioned broad and focused Python file queries for one named target.
PythonFileFactsOne Python file’s identity, source, and Fensu-owned fact, text, syntax, and relation zones.

Web facts

ModelDescribes
WebWorkspaceFactsVersioned TypeScript or Svelte target facts.
WebFileFactsOne discovered web source, its semantic facts, source, and parse result.
WebImportFactAuthored import bindings, flags, location, and optional resolved target.
WebFunctionFactFunction ownership, annotations, return type, and structural metrics.
WebClassFactClass identity, export status, and error-class classification.
WebModelFactInterface or type-literal model shape and readonly evidence.
WebBindingFactTop-level binding and optional initializer call.
WebCallFactNamed call, lexical function owner, ancestors, and cleanup evidence.
WebResourceFactStatically recognized resource family, binding, and call ancestry.
WebSyntaxHandleFensu-owned kind, name, location, and stable source byte range.
SvelteFileFactsComponent, route, state-module, script, and rune extensions.
SvelteScriptFactOne module or instance script block.
SvelteRuneFactOne recognized module-owned rune and source location.

Test facts

ModelDescribes
PytestFunctionFactSyntax metadata for one test function.
PytestModuleFactsModule-shape metadata for test policy.
ParametrizeFactStructured parametrization decorator metadata.
ParametrizeCaseFactOne visible parametrization case expression.
ParametrizeDimensionFactOne parametrization dimension and its provable RuleCase values.
EvaluateRuleCallFactOne statically recognized evaluate_rule call.
RuleTestAssociationFactStatic harness coverage for one test function and rule.