Configuration
Fatou is configured with a TOML file named fatou.toml. Every key is optional,
so a config only needs to mention what you want to change from the defaults.
Unknown keys are rejected with an error, which means a typo never silently falls
back to a default.
The dprint plugin uses the fatou object in
dprint.json for its settings and does not read fatou.toml.
A minimal project config looks like this:
exclude = ["vendored/"]
[format]
line-width = 100
[lint]
ignore = ["unused-argument"]
This guide covers the common tasks. For the exhaustive list of keys, their types, and their defaults, see the configuration reference.
Editor Support
Fatou publishes a JSON Schema for fatou.toml, so
editors with TOML support can offer key and value completion, inline
documentation, and validation while you edit the configuration.
Schema URL : https://fatou.dev/fatou.schema.json
The schema is generated from the same configuration types Fatou uses at runtime and checked for drift in the test suite.
VS Code and Even Better TOML
With the Even Better
TOML
extension installed, add this association to your user or workspace
settings.json:
{
"evenBetterToml.schema.associations": {
"^(.*/)?fatou\\.toml$": "https://fatou.dev/fatou.schema.json"
}
}
Inline Schema Directive
Editors that recognize Taplo’s schema directive can select the schema from the configuration file itself:
#:schema https://fatou.dev/fatou.schema.json
Other editors and language servers, including Helix, Neovim with taplo-lsp,
Zed, and IntelliJ, can use the same URL through their TOML schema association
settings.
Where Fatou Looks for a Config
For a given file, Fatou walks up from the file’s directory through its
ancestors, and uses the first fatou.toml it finds. The usual layout is a
single fatou.toml beside .git at the root of the project.
The walk stops at the repository root, so a fatou.toml parked above your
repository never governs the project inside it. The root itself is searched, and
a worktree or submodule checkout, whose .git is a file rather than a
directory, bounds the walk the same way. A directory with no .git ancestor
keeps walking to the filesystem root.
User-Wide Defaults
If you want the same settings across projects, do not put a fatou.toml above
your repositories; use a global config instead. When no project fatou.toml is
found, Fatou looks for one in your user config directory, typically
~/.config/fatou/fatou.toml.
To keep a config on a synced drive and point every machine at it, set the
FATOU_CONFIG environment variable to its path. A non-empty FATOU_CONFIG
shadows the global config entirely. An unset or empty value uses the normal user
config location. Relative paths resolve from the process’s working directory;
use an absolute path in editor settings.
In VS Code, add this to your user settings.json, then run Fatou: Restart
Server:
{
"fatou.serverEnv": {
"FATOU_CONFIG": "P:/Softwares/fatou.toml"
}
}
A missing or malformed config file makes the CLI fail. The language server logs a configuration warning in the Fatou output channel and uses editor settings or built-in defaults. Fix the file and restart the server to apply it.
FATOU_CONFIG and global configs are whole-file fallbacks, never merged with a
project config: as soon as a project fatou.toml is found, it is the only file
that applies. Relative exclude patterns in a FATOU_CONFIG or global file
resolve against the working directory (on the command line) or the document’s
directory (in the language server) rather than the config file’s own directory.
The language server uses the same resolution, so either file is a convenient way
to set editor-wide defaults. Only project files are watched, so an edit to a
global or FATOU_CONFIG file is picked up when the server restarts.
Bypassing Discovery
On the command line, --config <PATH> loads an explicit file and skips
discovery altogether, and --no-config ignores every file (project,
FATOU_CONFIG, and global) and runs with the built-in defaults.
Resolution Order
In full, Fatou uses the first source that applies:
--config <PATH>, which loads that file and skips discovery.--no-config, which ignores every file and uses the built-in defaults.- The nearest
fatou.toml, found by walking up from the file’s directory. The walk stops at the repository root (the directory holding.git, whether a directory or a file), inclusive; a directory with no.gitancestor is walked to the filesystem root. $FATOU_CONFIG, when set and non-empty. A missing or malformed file here is a configuration error.- The global user config: the first existing file among
$XDG_CONFIG_HOME/fatou/fatou.toml, when that variable is set~/.config/fatou/fatou.toml- the platform config directory, on macOS
~/Library/Application Support/fatou/fatou.toml
- The built-in defaults.
Sources are never merged: exactly one file is used.
Checking standalone scripts
Declare the files you run as independent programs to check undefined names across their static includes:
[project]
entry-points = ["scripts/main.jl"]
The CLI and language server enable undefined-name by default for each entry
point and its included files. An explicit [lint] select replaces those
defaults; ignore = ["undefined-name"] disables the rule. Files outside these
programs keep their usual defaults.
No Julia package is required. Paths are relative to the configuration file. If
main.jl includes settings.jl and worker.jl, functions in worker.jl can
use globals defined in settings.jl. Misspellings still produce warnings.
Separate entry points do not share globals, even when they include the same
helper file. Findings identify the entry point and module where the name is
undefined.
Run fatou lint . to check the discovered Julia files. Running
fatou lint scripts/main.jl reports findings only in that file; its includes
still supply resolution context. The language server also uses unsaved changes
in included files.
Fatou never executes Julia to analyze a script. Dynamic includes, eval,
unresolved whole-module imports, and missing or broken dependencies can prevent
it from proving a name undefined. Those entry points remain conservative; see
the project configuration reference for
the current limits.
Excluding files
exclude takes gitignore-style patterns, resolved relative to the directory
containing fatou.toml. Excluded directories are pruned during discovery, so
fatou format src and fatou lint src never descend into them.
exclude = ["vendored/"]
Use extend-exclude when you want to keep whatever exclude already lists and
add to it, which is mostly useful when the two live in different layers of your
setup:
extend-exclude = ["generated.jl"]
A file named explicitly on the command line is always processed, even if it
matches an exclude pattern. Pass --force-exclude to apply the patterns to
explicitly named files too; this is meant for runners like pre-commit, which
invoke Fatou with the staged files as arguments. Extra patterns can also be
supplied per run with --exclude on fatou format and fatou lint.
Formatting
The [format] table controls the formatter. The defaults follow common Julia
conventions, so most projects only set a key here to depart from them:
[format]
line-width = 92
indent-width = 4
line-ending = "auto"
line-width is the width the formatter tries to keep lines within, and
indent-width is the number of spaces per indentation level. Both can be
overridden per run with the --line-width and --indent-width flags on
fatou format.
line-ending decides the newline style. The default, auto, mirrors the source
file’s first line ending and falls back to lf when the file has none, which
keeps mixed checkouts stable. Use lf or crlf to force one style, or native
to follow the platform Fatou runs on.
Deprecation: the snake_case keys
line_widthandindent_widthare still accepted but print a warning. Use the kebab-caseline-widthandindent-widthinstead; the snake_case forms will be removed in a future release.
Choosing Lint Rules
By default most rules run; the rule reference lists the
few that are opt-in. Use extend-select to enable additional rules while
keeping the defaults. For example, to report undefined names in self-contained
files without configuring entry points or losing unused-variable warnings:
[lint]
extend-select = ["undefined-name"]
select, when set, replaces the default rule set. extend-select then adds to
that selection, and ignore turns individual rules off, including rules named
in extend-select:
[lint]
select = ["unused-binding", "unused-argument"]
extend-select = ["undefined-name"]
ignore = ["unused-argument"]
On the CLI, this configuration runs unused-binding and undefined-name. An
empty select = [] disables the defaults, leaving only rules in extend-select
that are not ignored. For workspace package files, the language server also
enables rules that need project resolution, unless they are ignored.
See the rule reference for the available rule IDs.
[lint.severity] changes how loudly a rule reports, without changing whether it
runs. Rules you do not list keep their default severity:
[lint.severity]
unused-binding = "warning"
undefined-name = "error"
Tuning a Rule
A rule with a tunable knob reads it from its own table, named after the rule ID.
For example,
discouraged-function ships a
deny-list of Base functions with process-wide or memory-unsafe effects, and you
can add your own entries to it:
[lint.rules.discouraged-function]
extend-functions = { sleep = "use a timer instead of blocking the task" }
Rules without options have no table. The configuration reference lists the rules that do.
Note that strictness here is deliberately different from select, ignore, and
severity. Those are lists of IDs you typed, so an unrecognized entry is only a
warning and the run continues. A [lint.rules.<id>] table is a schema, so a
misspelled rule ID, or a misspelled key inside one, is a configuration parse
error and the run stops.