Developer Tools

RAFF

Executable architecture fitness functions for Rust — statement count, module coupling and Git volatility as CI and pre-commit gates, so AI-generated code meets the same deterministic quality boundary as human-written code.

Active · 2025

Rust · CLI

RAFF

raff is a code-quality and architecture analysis tool for Rust projects.

It turns architectural expectations into executable fitness functions: measurable rules that can run locally, in continuous integration, or as part of a pre-commit hook. Rather than relying entirely on code review to notice structural degradation, raff makes selected qualities of a codebase continuously observable and enforceable.

I originally built it as a practical code-quality tool, but I also designed it with AI coding agents in mind.

As AI agents take on larger implementation tasks, generating code is no longer the difficult part. The harder problem is ensuring that the resulting code remains maintainable, appropriately decomposed, and consistent with the architecture of the repository. raff provides a deterministic quality boundary that sits outside the agent: generated code can be analysed before it is committed, and changes that exceed configured architectural thresholds can be rejected automatically.

Why I built it

Code quality often degrades gradually.

A file gains a few more responsibilities. A module starts depending on several neighbouring components. A supposedly stable area begins changing with every feature. None of these changes necessarily looks severe in isolation, but together they create systems that are harder to understand, test, and modify safely.

Traditional linters are effective at catching local implementation problems, but many architectural concerns exist above the level of individual expressions:

  • Is one component becoming disproportionately large?
  • Are module boundaries becoming increasingly coupled?
  • Which parts of the codebase change most often?
  • Are frequently changing components also highly connected?
  • Is a proposed change moving the architecture towards or away from its intended shape?

raff is intended to make questions like these measurable.

It is based on the idea of architecture fitness functions: automated checks that continuously evaluate whether a system still exhibits the characteristics its developers want to preserve.

What it analyses

Statement count

raff can count statements across Rust files and directories.

Statement count is not a complete measure of complexity, but it is a useful structural signal. It can reveal files, modules, or components that are accumulating too much responsibility and may need to be decomposed.

raff statement-count --path ./src

Rather than treating every large file as inherently wrong, teams can use configurable thresholds to identify significant outliers and architectural drift.

Module coupling

raff analyses dependencies between Rust modules and components.

This makes it easier to see where boundaries are becoming porous, where internal modules have accumulated too many outward dependencies, and where changes may have an unexpectedly broad impact.

raff coupling --path ./src

Coupling analysis is particularly useful in layered systems, modular monoliths, and repositories organised around bounded contexts or vertical slices. It gives developers a concrete way to evaluate whether those intended boundaries are reflected in the code.

Code volatility

raff uses Git history to identify which parts of a repository change most frequently.

raff volatility --path .

High volatility is not automatically a defect. A component may change frequently because it represents an actively developed part of the product. The value comes from combining volatility with other signals.

A component that changes often and is also highly coupled deserves attention: it may amplify the cost and risk of every change made around it.

Combined architecture checks

The analyses can be run together through a single command:

raff all

This provides a broader view of the repository and makes it suitable for automated quality gates.

Designed for AI-assisted development

One of the reasons I built raff was to improve the reliability of AI-generated code.

AI coding agents are effective at completing well-scoped implementation tasks, but they can optimise too heavily for the immediate request. An agent may produce code that compiles and passes tests while still:

  • adding responsibility to an already oversized module;
  • introducing unnecessary dependencies between components;
  • duplicating logic across architectural boundaries;
  • placing code in a convenient rather than appropriate location;
  • increasing the change surface of a frequently modified component;
  • satisfying the feature request while weakening the overall design.

Human review remains important, but it should not be the only defence.

raff gives a repository a deterministic architectural feedback loop. The same rules apply regardless of whether code was written manually, generated by an agent, or produced through a combination of both.

A useful workflow is:

  1. An AI agent implements a task.
  2. Tests, formatting, and conventional linting run.
  3. raff analyses the staged architectural impact.
  4. The commit proceeds only if the configured fitness functions pass.
  5. If a threshold is exceeded, the agent receives concrete feedback about the affected component and can revise the implementation.

This moves architectural quality from a prompt-level suggestion into an executable repository constraint.

Instead of merely telling an agent to “keep the architecture clean”, the repository can define what selected aspects of clean architecture mean and verify them automatically.

Pre-commit integration

raff includes a pre-commit-oriented profile designed to keep local feedback fast.

repos:
  - repo: local
    hooks:
      - id: raff-architecture-check
        name: Architecture fitness functions
        entry: raff --profile pre-commit all
        language: system
        pass_filenames: false
        always_run: true

The pre-commit profile focuses on staged files and fast analyses, avoiding slower history-based work when appropriate.

This makes it suitable for both human and agent-driven workflows. An AI agent can make a change, stage it, and run the same checks that a developer would encounter before committing.

The result is a tighter correction loop: architectural problems are caught while the implementation context is still active, rather than later during pull-request review.

Configurable quality boundaries

raff can be configured through a repository-level configuration file:

[profile.pre_commit]
fast = true
staged = true
quiet = true
sc_threshold = 25

This allows each repository to define quality boundaries appropriate to its own architecture.

The intent is not to impose a universal definition of good design. A low-level parser, a command-line entry point, and a domain service may have very different acceptable shapes. Fitness functions are most valuable when they encode deliberate local decisions rather than generic style opinions.

Configuration can be used to determine:

  • which analyses run;
  • whether only staged files are inspected;
  • how strict thresholds should be;
  • which paths or components are included;
  • what output format is produced;
  • whether a violation should fail the command.

Multiple output formats

raff can produce results for both humans and automation.

Supported output styles include terminal-oriented reports as well as machine-readable and visual formats such as:

  • JSON
  • CSV
  • HTML
  • Graphviz DOT
  • JUnit-compatible output
  • Static Analysis Results Interchange Format

Human-readable output is useful during local development. Structured formats make the same analyses suitable for continuous integration systems, dashboards, pull-request annotations, and other developer tooling.

Graph output can also make coupling relationships easier to inspect visually than through raw dependency lists.

Architecture as an executable property

The central idea behind raff is that architecture should not exist only in diagrams, documentation, or the memories of senior engineers.

Those things are valuable, but they are passive. They do not automatically react when the code stops matching the intended design.

Fitness functions turn selected architectural decisions into executable properties of the repository.

They cannot prove that an architecture is good, and they should not replace engineering judgement. What they can do is continuously surface measurable drift:

  • components growing beyond intended limits;
  • dependency direction becoming less controlled;
  • volatile areas accumulating broader coupling;
  • code changes crossing boundaries unexpectedly.

That is especially valuable as repositories grow and more implementation work is delegated to autonomous tools.

Installation

Install the command-line tool with Cargo:

cargo install raff-cli

The installed binary is named raff:

raff --help

It can also be installed directly from the repository during development:

cargo install --git https://github.com/liamwh/raff.git

Design principles

Architecture rules should be executable

An architectural rule that cannot be checked is easy to ignore accidentally. raff focuses on turning useful structural signals into repeatable commands.

Results should be actionable

A quality tool should identify the affected component, explain the relevant metric, and provide enough context for a developer or coding agent to improve the change.

Local feedback should be fast

The pre-commit path should analyse only what is needed and avoid expensive work that belongs in continuous integration or an explicit full-repository analysis.

Rules should be configurable

Architecture is contextual. Thresholds and boundaries should reflect the repository rather than imposing arbitrary universal limits.

AI-generated code should meet the same standards

The origin of a change should not affect its quality bar. Human-written and AI-generated code should pass the same tests, lint rules, and architectural fitness functions.

Metrics support judgement rather than replacing it

Statement count, coupling, and volatility are signals. They help focus attention and support decisions, but they are not substitutes for understanding the code.

Status

raff is an open-source Rust project and command-line tool.

Its current capabilities centre on statement-count analysis, module coupling, Git-based code volatility, configurable profiles, staged-file analysis, pre-commit integration, and multiple report formats.

The longer-term direction is to expand the set of architecture fitness functions while keeping them practical, configurable, and useful as automated quality gates for both developers and AI coding agents.

Open chat

Interested in working together? Reach out.

Strategy, architecture, and implementation — from workflow to production.

© 2026 Liam Woodleigh. All rights reserved.