Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Configuration

Arity is configured with a TOML file named arity.toml. All keys are optional; omitting a key uses its default. Keys are kebab-case, and unknown keys are rejected with an error (so a typo never silently falls back to a default).

Run arity init to write a commented starter file.

Editor support

Arity publishes a JSON Schema for arity.toml, so editors with TOML support can offer completion, inline documentation, and validation while you edit your configuration.

Schema URL : https://arity.cc/arity.schema.json

The schema is generated from Arity’s configuration types and checked against the repository’s own arity.toml. It therefore stays aligned with the keys, enums, constraints, and defaults accepted by the CLI. The version at the published URL tracks the latest Arity release.

Until arity.toml is registered with SchemaStore, editors need a manual association. With the Even Better TOML extension for VS Code, add this to your user or workspace settings.json:

{
  "evenBetterToml.schema.associations": {
    "^(.*/)?arity\\.toml$": "https://arity.cc/arity.schema.json"
  }
}

Editors and language servers that recognize TOML schema directives can instead put this comment at the top of arity.toml:

#:schema https://arity.cc/arity.schema.json

Other editors—including Neovim with taplo-lsp, Helix, Zed, and IntelliJ—can use the same URL through their JSON Schema association settings.

Discovery

For a given file, arity looks for arity.toml by walking up from the file’s directory through its ancestors, stopping at the first arity.toml it finds or at a directory containing a .git entry (the repository root), whichever comes first.

If no project config is found, arity loads the file named by the ARITY_CONFIG environment variable. This lets you keep a user config at a custom location, such as a synced drive. Project configs take precedence and replace the user config entirely; files from different discovery steps are not merged.

Relative ARITY_CONFIG paths resolve from the process’s working directory. An absolute path is recommended for editor settings. An unset or empty value uses the built-in defaults when no project config is found. A missing or invalid fallback file is a configuration error.

To share settings between projects, put extend = "../shared/arity.toml" at the top level of a project config. Arity resolves the path relative to the file that declares it (and expands a leading ~/ to your home directory), then merges the referenced config before the current file. Chains are allowed, and a cycle or missing file is an error. Child values override inherited values; tables merge by key, so overriding [format] line-width keeps an inherited indent-width. extend-exclude arrays append in base-to-child order, while exclude replaces the inherited array. For a project config or --config file, the selected file still anchors exclude patterns, even when they come from an extended file.

On the command line:

  • --config <PATH> loads an explicit file and skips project discovery and ARITY_CONFIG.
  • --no-config ignores all config files, including ARITY_CONFIG, and uses the built-in defaults.

In VS Code or Positron, set the variable in your user settings.json, then run Arity: Restart Server:

{
  "arity.serverEnv": {
    "ARITY_CONFIG": "P:/Softwares/arity.toml"
  }
}

Exclude patterns in a project config or an explicit --config file resolve relative to that file’s directory. The ARITY_CONFIG fallback has no project location, so its patterns resolve relative to the working directory for CLI walks, or the directory being scanned in the language server.

Top-level keys

These apply to both format and lint. exclude and extend-exclude govern the shared file walk.

KeyTypeDefaultDescription
extendstringunsetPath to another config file, resolved relative to this file.
excludearray of stringsbuilt-in setgitignore-style patterns to skip, anchored according to the config source. Setting it replaces the built-in set (below).
extend-excludearray of strings[]Like exclude, but added to exclude rather than replacing it. Use this to skip extra paths while keeping the built-in defaults.
cachebooleantrueEnable the persistent result cache (currently the format --check already-formatted cache; the cache directory follows [index] cache-dir/$ARITY_CACHE_DIR). The --no-cache CLI flag overrides it per run.

The built-in default exclude set (the default value of exclude; generated or vendored files that should not be reformatted or linted) is:

.git/
renv/
revdep/
cpp11.R
RcppExports.R
extendr-wrappers.R
import-standalone-*.R

Excludes apply only to directory walks. A file named explicitly on the command line is always processed, even if it matches an exclude pattern. Pass --force-exclude (on format and lint) to apply the patterns to explicitly named files too—useful for runners like pre-commit that pass staged files as arguments. The CLI flag --exclude <PATTERN> (on format and lint) adds to the configured exclude/extend-exclude for a single run.

# Keep the built-in defaults and also skip these:
extend-exclude = ["vendor/", "*.gen.R"]

# Or replace the built-in defaults entirely:
# exclude = ["vendor/", "*.gen.R"]

[format]

KeyTypeDefaultDescription
line-widthinteger (1–1000)80The width the formatter tries to keep lines within. Not a hard cap.
indent-widthinteger (1–1000)2Number of spaces per indentation level.
line-endingstring"auto"Newline style: "auto", "lf", "crlf", or "native" (see below).
roxygenbooleantrueWhether to format #' blocks in R files.
descriptionbooleantrueWhether a package DESCRIPTION is formatted.

line-ending = "auto" mirrors the source file’s first line ending (defaulting to lf when the file has none); "native" is crlf on Windows and lf elsewhere; "lf" and "crlf" force that ending.

[format]
line-width = 80
indent-width = 2
line-ending = "auto"
roxygen = true
description = true

line-width and indent-width can be overridden per run with the --line-width/--indent-width flags on arity format. They apply to DESCRIPTION too, except that its continuation indent is always four spaces — the file format’s convention, and a different axis from R-code nesting.

Set roxygen = false to keep each #' block’s source layout while formatting the R code around it. This also preserves #' blocks used as Markdown prose by knitr::spin(). The file’s configured line-ending still applies to the output.

Setting description = false leaves DESCRIPTION alone, in the CLI (including a buffer piped in under --stdin-filename DESCRIPTION, which is passed through untouched) and in the editor. Reach for it if arity and your package tooling end up disagreeing about the file. Note that extend-exclude is not a substitute: excludes are shared with the linter, so excluding DESCRIPTION would also silence the packaging rules, and the language server applies no exclude filter to formatting at all.

[lint]

KeyTypeDefaultDescription
selectarray of stringsunsetIf set, only these rule IDs run.
ignorearray of strings[]Rule IDs to disable (applied on top of select or the default set).

Rule IDs are the kebab-case names from the rule reference. Unknown IDs are reported when linting runs, not when the config is parsed. The --select/--ignore flags on arity lint override these for a single run.

[lint]
select = ["undefined-symbol", "equals-na"]
ignore = ["unused-binding"]

[lint.rules.<id>]

A few rules take options of their own, set in a table named after the rule ID. Rules that take no options have no table.

Unlike select/ignore—where rule IDs are data, checked when linting runs—a rule ID here is part of the schema, so a mistyped one is reported when the config is parsed, alongside any other unknown key.

[lint.rules.undesirable-function]

The function-name policy for undesirable-function.

KeyTypeDefaultDescription
functionstable of name → hintbuilt-in setFlagged functions. Replaces the built-in set.
extend-functionstable of name → hint{}Entries added on top of functions, overriding same-named ones.

The value is the advice shown as the diagnostic’s suggestion; an empty string means “no alternative, just don’t call this”. The functions/extend-functions split works like exclude/extend-exclude: reach for extend-functions unless you really mean to discard the built-in set. Setting functions = {} silences the rule entirely.

The built-in set covers base-R functions that mutate global state (attach, detach, .libPaths, install.packages, setwd, sink, source, options, par, Sys.setenv, Sys.setlocale) and the debugging entry points (debug, debugonce, undebug, trace, untrace). browser() is deliberately absent: it has its own browser rule.

[lint]
select = ["undesirable-function"]

[lint.rules.undesirable-function]
extend-functions = { sapply = "use `vapply()` for a stable return type" }

[compat]

The minimum tool versions the project supports, in the spirit of clippy’s msrv and ruff’s target-version. Consumed by the version-aware lint rules (r-compat, roxygen2-compat): syntax or documentation constructs that need a newer version than the declared floor are flagged.

KeyTypeDefaultDescription
rversion stringunsetMinimum supported R version, e.g. "4.1".
roxygen2version stringunsetThe roxygen2 version the project documents with, e.g. "7.3.2".

Values are plain version strings—the key is the >= floor, so there is no operator syntax.

When a key is unset, the floor is derived per file from the enclosing package’s DESCRIPTION: Depends: R (>= …) supplies r, and Config/roxygen2/version (written by roxygen2 8.0.0 and later) or the legacy RoxygenNote supplies roxygen2. An explicit key here always wins. With neither a key nor a DESCRIPTION fact, the version-aware rules stay silent, so loose scripts see no false positives.

[compat]
r = "4.1"
roxygen2 = "7.3.2"

[index]

Controls the R-package symbol index used by the language server (and by namespace-aware lint rules) to resolve names.

KeyTypeDefaultDescription
library-pathsarray of paths[]Explicit R library directories, used when automatic discovery misses.
cache-dirpathunsetOverride the index cache directory (otherwise XDG/$ARITY_CACHE_DIR).
auto-buildbooleantrueLet the language server lazily index referenced-but-unindexed packages.
helpbooleantrueHarvest help titles while indexing. false stores names only (faster).

Note: the downloadable CRAN symbol sidecar is not configured here. Enabling network access is a per-user decision set via the ARITY_REMOTE_URL environment variable, never committed in a shared arity.toml.

Note: the same applies to the attach probe (arity index --attach-probe), which observes what a meta-package attaches by running library() in a fresh R session. Because that executes package attach hooks, it is enabled per run by the flag or per user via the ARITY_ATTACH_PROBE environment variable, never from arity.toml. Without it, attach sets are still captured for packages following the tidyverse core convention, with a built-in table as the offline fallback.

Reserved for future use

The following are not yet implemented but are reserved so the schema can grow without breaking changes (adding a key is always backward-compatible under the strict unknown-key check):

  • [format].indent-style ("space" or "tab")—tab indentation.
  • [format].skip and a # fmt: skip comment—opt specific calls out of formatting.
  • severity in a [lint.rules.<id>] table—overriding a rule’s severity.
  • Category names (e.g. "correctness") in select/ignore.