Skip to main content
fensu init sets up Fensu in a repository. It detects your layout, writes a fensu.toml with the complete default ruleset, runs an initial check to show the current drift, and offers to install agent skill files. It never guesses silently: every detected path shows where it came from, and nothing is written until you confirm (or pass --yes).

What it does

  1. Detects your layout. Package roots come from pyproject.toml metadata (hatch, setuptools, poetry, flit, uv workspaces, the project name), ruff’s src setting, and a directory scan. Test paths come from pytest testpaths and tests/test directories; tooling from scripts, tools, bin, and tasks directories with Python files. If package metadata also names one of those conventional tooling directories, tooling classification wins so a path is never proposed in both scopes; an explicit --root overrides detection.
  2. Enables the complete ruleset. Every repository gets select = ["FF"]. An empty repository also gets a scaffolded src/<name>/ package plus tests/.
  3. Writes fensu.toml and updates your .gitignore to cover Fensu’s cache directory.
  4. Measures current drift by running the starting ruleset once and printing per-family fault counts.
  5. Installs project-specific agent skill files (.claude/, .opencode/, .agents/) at the Git root unless you decline; see fensu skills.

Options

--skills and --no-skills are mutually exclusive. --root, --tests, and --tooling only apply when a codebase is detected; --name only applies when none is.

An existing repository

On a repository with code, fensu init shows what it detected and why, then confirms before writing:
Answering e at the confirmation lets you edit the paths; n aborts without writing anything. When several package roots are detected, you pick which to include by number. No rule family is silently held back. For an existing repository, keep the target visible and roll it out with evaluation targeting or explicit rule exceptions; see Adopting Fensu.

An empty repository

With no Python code detected, fensu init scaffolds a fresh layout instead. In an interactive terminal it asks for a package name and offers the directory name as a default. Non-interactive --yes cannot confirm that derived name, so it requires --name:
The resulting project starts fully enforced from the first commit:

Gitignore handling

Fensu’s generated result cache lives under .fensu/cache/, which should not be committed. The rest of the .fensu/ namespace is not ignored automatically.
  • If a root .gitignore exists and does not already cover the cache path, fensu init appends a .fensu/cache/ entry to it.
  • An empty repository with no .gitignore gets one created from the standard GitHub Python template, plus the .fensu/cache/ entry.
  • An existing repository with no .gitignore gets one containing just the .fensu/cache/ entry.

Rerunning is safe

If the directory already has a fensu.toml or a [tool.fensu] table, fensu init changes nothing and exits 0:
If a parent directory’s configuration would apply here instead, init refuses with an error rather than shadowing it. Configuration and scaffold writes are transactional. Drift measurement and skill installation happen afterward. If skill installation fails, the initialized project is kept and the error is reported so you can rerun fensu skills.

Non-interactive use

Prompts require a terminal. In CI or scripts, pass --yes (or make every choice explicit with flags); otherwise init fails:

Exit codes

Quickstart

The manual version of what init automates.

Adopting Fensu

Rolling out full enforcement with explicit boundaries and exceptions.

Configuration

Every key in the file init writes.

fensu skills

The agent guidance init offers to install.