---
title: Configuration
---

Panache aims to provide sensible defaults, but also be configurable enough to
accommodate common formatting preferences.

The configuration system is built around a TOML configuration file, which allows
you to customize a range of options, including formatting preferences, linting
rules, external linter and formatter integrations>

Panache searches for a configuration file in the following order:

1. **Explicit path**: `--config <path>` (errors if invalid)
2. **Project config**: `.panache.toml` or `panache.toml` in current or parent
   directories
3. **User config**: `~/$XDG_CONFIG_HOME/panache/config.toml` (typically
   `~/.config/panache/config.toml`)

## Basic Options

Here, we list the top-level configuration options that control general behavior.

### Flavor

Choose the Markdown flavor, which determines default [extension](#extensions)
settings:

```toml
flavor = "pandoc"
```

The available flavors are:

`pandoc`
:   Standard [Pandoc Markdown](https://pandoc.org) (default)

`quarto`
:   [Quarto](https://quarto.org)-flavored Markdown (Pandoc + Quarto extensions)

`rmarkdown`
:   R Markdown (Pandoc + R-specific extensions, including Bookdown): R Markdown
    (Pandoc + R-specific extensions)

`gfm`
:   GitHub-Flavored Markdownb Flavored Markdown

`commonmark`
:   CommonMark (Note that we are currently **not** fully CommonMark-compliant,
    and use this option only as a means to setup the correct set of extensions):
    CommonMark (minimal extensions)

### Line Width

Set the maximum line width for text wrapping:

```toml
line-width = 80
```

### Flavor Overrides

Use `flavor-overrides` to pick flavor by path pattern for Markdown-family files
(`.md`, `.markdown`, `.mdown`, `.mkd`):

```toml
flavor = "quarto"

[flavor-overrides]
"README.md" = "gfm"
"docs/**/*.md" = "quarto"
```

Panache applies flavor in this order:

1. `.qmd` files always use `quarto`
2. `.Rmd` files always use `rmarkdown`
3. Markdown-family files use the most specific matching `flavor-overrides`
   pattern
4. Otherwise, Panache falls back to top-level `flavor`

### File Selection (Directory Traversal)

When you run commands on directories (`panache format .`, `panache lint .`,
`panache debug format .`), Panache supports include/exclude selectors:

```toml
exclude = [".git/", "build/"]
extend-exclude = ["tests/testthat/_snaps/"]
include = ["*.qmd", "*.md"]
extend-include = ["*.Rmd"]
```

`exclude`
:   Base exclude patterns. If set, replaces Panache's default exclude base. The
    default exclude base includes common build/cache directories and
    `**/LICENSE.md`.

`extend-exclude`
:   Additional exclude patterns appended to the base set.

`include`
:   Base include patterns. If set, replaces Panache's default include base.

`extend-include`
:   Additional include patterns appended to the base set.

If a path matches both include and exclude, exclude wins.

## Formatting Style

Formatting style preferences are organized under the `[format]` section:

```toml
[format]
wrap = "reflow"
blank-lines = "collapse"
math-delimiter-style = "preserve"
math-indent = 0
tab-stops = "normalize"
tab-width = 4
```

### Wrapping Mode

Control how text is wrapped:

```toml
[format]
wrap = "reflow"
```

`reflow`
:   Reformat paragraphs to fit within line width (default)

`sentence`
:   Wrap after each sentence.

`preserve`
:   Keep existing line breaks

### Blank Lines

Control blank line handling:

```toml
[format]
blank-lines = "collapse"
```

`collapse`
:   Collapse multiple blank lines into one (default)

`preserve`
:   Keep all existing blank lines

### Math Formatting

Configure how math delimiters are formatted:

```toml
[format]
math-delimiter-style = "preserve"
math-indent = 0
```

Math delimiter styles:

`preserve`
:   Keep original delimiter style (default)

`dollars`
:   Normalize to `$...$` and `$$...$$`

`backslash`
:   Normalize to `\(...\)` and `\[...\]`

The `math-indent` field specifies indentation (in spaces) for display math
blocks. Default is 0.

### Tab Stops

Control how tabs are handled during formatting:

```toml
[format]
tab-stops = "normalize"
tab-width = 4
```

`normalize`
:   Convert tabs to spaces using `tab-width` (default 4).

`preserve`
:   Preserve tabs in literal code spans and fenced/indented code blocks. Tabs in
    regular text are always normalized to spaces.

`tab-width`
:   Number of spaces per tab when normalizing (default 4).

## Extensions

Panache supports most of the Pandoc extensions. Defaults vary by flavor, but you
can override any extension:

```toml
flavor = "quarto"

[extensions]
hard-line-breaks = false
citations = true
task-lists = true
```

You can also scope extension overrides to a specific flavor:

```toml
[extensions]
citations = true
task-lists = false

[extensions.gfm]
task-lists = true
```

Precedence for the active flavor is:

1. flavor defaults
2. global `[extensions]`
3. `[extensions.<flavor>]`

### Block-Level Extensions

#### Headings

```toml
[extensions]
blank-before-header = true
header-attributes = true
implicit-header-references = true
```

`blank-before-header`
:   Require blank line before headers (default: enabled)

`header-attributes`
:   Full attribute syntax on headers `{#id .class key=value}` (default: enabled)

`implicit-header-references`
:   Allow `[Heading]` links to reference headers (default: enabled)

#### Block Quotes

```toml
[extensions]
blank-before-blockquote = true
```

`blank-before-blockquote`
:   Require blank line before blockquotes (default: enabled)

#### Lists

```toml
[extensions]
fancy-lists = true
startnum = true
example-lists = true
task-lists = true
definition-lists = true
```

`fancy-lists`
:   Roman numerals, letters, and fancy list markers (default: enabled)

`startnum`
:   Start ordered lists at arbitrary numbers (default: enabled)

`example-lists`
:   Example lists with `(@)` markers (default: enabled)

`task-lists`
:   GitHub-style task lists `- [ ]` and `- [x]` (default: enabled)

`definition-lists`
:   Term/definition syntax (default: enabled)

#### Code Blocks

```toml
[extensions]
backtick-code-blocks = true
fenced-code-blocks = true
fenced-code-attributes = true
inline-code-attributes = true
```

`backtick-code-blocks`
:   Fenced code blocks with \`\`\` fences (default: enabled)

`fenced-code-blocks`
:   Fenced code blocks with `~~~` fences (default: enabled)

`fenced-code-attributes`
:   Attributes on fenced code blocks `{.language #id}` (default: enabled)

`inline-code-attributes`
:   Attributes on inline code `` `code`{.class} `` (default: enabled)

#### Tables

```toml
[extensions]
simple-tables = true
multiline-tables = true
grid-tables = true
pipe-tables = true
table-captions = true
```

`simple-tables`
:   Simple table syntax (default: enabled)

`multiline-tables`
:   Multiline cells (default: enabled)

`grid-tables`
:   Grid-style tables (default: enabled)

`pipe-tables`
:   GitHub-style `|` tables (default: enabled)

`table-captions`
:   Table captions (default: enabled)

#### Divs

```toml
[extensions]
fenced-divs = true
native-divs = true
```

`fenced-divs`
:   Fenced divs `::: {.class}` (default: enabled)

`native-divs`
:   HTML `<div>` elements (default: enabled)

#### Other Blocks

```toml
[extensions]
line-blocks = true
```

`line-blocks`
:   Line blocks for poetry with `|` prefix (default: enabled)

### Inline Extensions

#### Emphasis

```toml
[extensions]
intraword-underscores = true
strikeout = true
superscript = true
subscript = true
```

`intraword-underscores`
:   Don't trigger emphasis in `snake_case` (default: enabled)

`strikeout`
:   Strikethrough `~~text~~` (default: enabled)

`superscript`
:   Superscript `^super^` (default: enabled)

`subscript`
:   Subscript `~sub~` (default: enabled)

#### Links

```toml
[extensions]
inline-links = true
reference-links = true
shortcut-reference-links = true
link-attributes = true
autolinks = true
autolink-bare-uris = false
```

`inline-links`
:   Inline links `[text](url)` (default: enabled)

`reference-links`
:   Reference links `[text][ref]` (default: enabled)

`shortcut-reference-links`
:   Shortcut reference links `[ref]` (default: enabled)

`link-attributes`
:   Attributes on links `[text](url){.class}` (default: enabled)

`autolinks`
:   Automatic links `<http://example.com>` (default: enabled)

`autolink-bare-uris`
:   Bare URLs become links (default: disabled, non-default extension)

#### Images

```toml
[extensions]
inline-images = true
implicit-figures = true
```

`inline-images`
:   Inline images `![alt](url)` (default: enabled)

`implicit-figures`
:   Single image becomes figure (default: enabled)

#### Math

```toml
[extensions]
tex-math-dollars = true
tex-math-gfm = false
tex-math-single-backslash = false
tex-math-double-backslash = false
```

`tex-math-dollars`
:   Dollar-delimited math `$x$` and `$$equation$$` (default: enabled)

`tex-math-gfm`
:   GFM math: inline `$`...`$` and fenced ```` ``` math ```` blocks (default:
    disabled, enabled for GFM flavor)

`tex-math-single-backslash`
:   Single backslash math `\(...\)` and `\[...\]` (default: disabled, enabled
    for RMarkdown)

`tex-math-double-backslash`
:   Double backslash math `\\(...\\)` and `\\[...\\]` (default: disabled)

#### Footnotes

```toml
[extensions]
inline-footnotes = true
footnotes = true
```

`inline-footnotes`
:   Inline footnotes `^[text]` (default: enabled)

`footnotes`
:   Reference footnotes `[^1]` and `[^1]: content` (default: enabled)

#### Citations

```toml
[extensions]
citations = true
```

`citations`
:   Citation syntax `[@cite]` (default: enabled)

#### Spans

```toml
[extensions]
bracketed-spans = true
native-spans = true
```

`bracketed-spans`
:   Bracketed spans `[text]{.class}` (default: enabled)

`native-spans`
:   HTML `<span>` elements (default: enabled)

### Metadata Extensions

```toml
[extensions]
yaml-metadata-block = true
pandoc-title-block = true
```

`yaml-metadata-block`
:   YAML frontmatter with `---` delimiters (default: enabled)

`pandoc-title-block`
:   Pandoc title block `% Title`, `% Author`, `% Date` (default: enabled)

### Raw Content Extensions

```toml
[extensions]
raw-html = true
markdown-in-html-blocks = false
raw-tex = true
raw-attribute = true
```

`raw-html`
:   HTML blocks and inline HTML (default: enabled)

`markdown-in-html-blocks`
:   Markdown inside HTML blocks (default: disabled)

`raw-tex`
:   LaTeX commands and environments (default: enabled)

`raw-attribute`
:   Generic raw blocks with `{=format}` syntax (default: enabled)

### Special Character Extensions

```toml
[extensions]
all-symbols-escapable = true
escaped-line-breaks = true
hard-line-breaks = false
emoji = false
mark = false
```

`all-symbols-escapable`
:   Backslash escapes any symbol (default: enabled)

`escaped-line-breaks`
:   Backslash at line end creates hard line break (default: enabled)

`hard-line-breaks`
:   Newline creates hard line break (default: disabled, non-default extension)

`emoji`
:   Emoji syntax `:emoji:` (default: disabled, non-default extension)

`mark`
:   Highlighted text `==highlighted==` (default: disabled, non-default
    extension)

### Quarto-Specific Extensions

```toml
[extensions]
quarto-callouts = true
quarto-crossrefs = true
quarto-shortcodes = true
```

`quarto-callouts`
:   Quarto callout blocks `.callout-note`, `.callout-warning`, etc. (default:
    disabled, enabled for Quarto flavor)

`quarto-crossrefs`
:   Quarto cross-references `@fig-id`, `@tbl-id` (default: disabled, enabled for
    Quarto flavor)

`quarto-shortcodes`
:   Quarto shortcodes `{{< name args >}}` (default: disabled, enabled for Quarto
    flavor)

### Bookdown Extensions

```toml
[extensions]
bookdown-references = true
```

`bookdown-references`
:   Bookdown references `\@ref(label)` and `(\#label)` (default: disabled,
    enabled for RMarkdown flavor)

## External Code Formatters

Panache can invoke external formatters for code blocks. Formatters are
opt-in—you choose which languages to format.

YAML is special: Panache has built-in YAML formatting for frontmatter and
hashpipe chunk options. External YAML formatters apply only to fenced code
blocks with YAML language. The YAML parser/formatter path is implemented in
Panache-owned in-repo components.

### Basic Usage

Map languages to formatters using built-in presets:

```toml
[formatters]
r = "air"
python = "ruff"
javascript = "prettier"
typescript = "prettier"
```

Available presets:

| Language | Preset         | Command                                 | Type       |
| -------- | -------------- | --------------------------------------- | ---------- |
| R        | `air`          | `air format {}`                         | File-based |
| R        | `styler`       | `Rscript -e "styler::style_file('{}')"` | File-based |
| Python   | `ruff`         | `ruff format`                           | Stdin      |
| Python   | `black`        | `black -`                               | Stdin      |
| YAML     | `yamlfmt`      | `yamlfmt -`                             | Stdin      |
| YAML     | `prettier`     | `prettier --parser=yaml`                | Stdin      |
| TOML     | `taplo`        | `taplo format -`                        | Stdin      |
| Shell    | `shfmt`        | `shfmt -`                               | Stdin      |
| C/C++    | `clang-format` | `clang-format -`                        | Stdin      |

### Sequential Formatting

Run multiple formatters in order by using an array:

```toml
[formatters]
python = ["isort", "black"]
```

Output from the first formatter is piped to the second.

### Custom Formatters

Define custom formatter configurations with the `[formatters.NAME]` syntax:

```toml
[formatters]
python = ["isort", "black"]
javascript = "prettier"

[formatters.prettier]
cmd = "prettier"
args = ["--parser=babel", "--print-width=100"]
stdin = true

[formatters.isort]
cmd = "isort"
args = ["-"]
stdin = true
```

Formatter definition fields:

`cmd`
:   Command to execute (required for custom formatters)

`args`
:   Command-line arguments (optional, defaults to empty list)

`stdin`
:   Use stdin/stdout mode (default: `true`) or file-based mode (`false`)

### Preset Inheritance

When a `[formatters.NAME]` section matches a built-in preset name, unspecified
fields are automatically inherited from the preset. This allows partial
overrides:

```toml
[formatters]
r = "air"

[formatters.air]
args = ["format", "--preset=tidyverse"]
```

In this example, `cmd` and `stdin` are inherited from the built-in `air` preset,
while `args` is customized.

How it works:

- If the formatter name matches a built-in preset (`air`, `black`, `ruff`,
  etc.), that preset's defaults are used as a base
- Any fields you specify (`cmd`, `args`, `stdin`) override the preset defaults
- Unspecified fields keep the preset values

Examples:

Override only `args` (inherits `cmd = "air"`, `stdin = false`):

```toml
[formatters.air]
args = ["format", "--custom-flag", "{}"]
```

Override only `cmd` (inherits default `args` and `stdin`):

```toml
[formatters.ruff]
cmd = "ruff-custom"
```

Override everything (complete replacement):

```toml
[formatters.black]
cmd = "my-black"
args = ["--fast"]
stdin = false
```

### Incremental Argument Modification

Instead of completely overriding `args`, you can append and prepend arguments to
the preset's base `args` using `append-args` and `prepend-args`:[^1]

```toml
[formatters]
r = "air"

[formatters.air]
append-args = ["-i", "2"]
```

This adds `["-i", "2"]` after the preset's base args `["format", "{}"]`,
resulting in final args `["format", "{}", "-i", "2"]`.

Available modifiers:

`prepend-args`
:   Arguments added before base args

`append-args`
:   Arguments added after base args

Multiple modifiers example:

```toml
[formatters.air]
prepend-args = ["--verbose"]
append-args = ["-i", "2", "--check"]
```

This produces final args: `["--verbose", "format", "{}", "-i", "2", "--check"]`.

With explicit args (no preset):

```toml
[formatters.shfmt]
cmd = "shfmt"
args = ["-filename", "$FILENAME"]
append-args = ["-i", "2", "-bn"]
```

Final args: `["-filename", "$FILENAME", "-i", "2", "-bn"]`.

[^1]: The idea of `append-args` and `prepend-args` is taken from the
    [conform.nvim](https://github.com/stevearc/conform.nvim) Neovim plugin.

### File-Based Formatters

For formatters that modify files in place:

```toml
[formatters]
r = "air-file"

[formatters.air-file]
cmd = "air"
args = ["format", "{}"]
stdin = false
```

The `{}` placeholder controls where the file path is inserted. If omitted, it's
appended at the end.

### Behavior

Language matching
:   Code block language (e.g., ```` ```python ````) is matched to formatter key
    (case-insensitive)

Parallel execution
:   All formatters run concurrently for speed

Sequential chains
:   Multiple formatters per language run in order

Error handling
:   Failed formatters preserve original code with a warning

Timeout
:   30 seconds per formatter (not per chain)

Config files
:   Formatters respect their own config files (`.prettierrc`, `pyproject.toml`,
    etc.)

## External Code Linters

Panache can invoke external linters for code blocks. Linters are opt-in—you
choose which languages to lint.

### Quick Start

Enable linters for specific languages:

```toml
[linters]
r = "jarl"
```

Available linters:

| Language | Linter | Command | Notes                          |
| -------- | ------ | ------- | ------------------------------ |
| R        | `jarl` | `jarl`  | R linter with JSON diagnostics |

### How It Works

External linters analyze code blocks within your document:

1. **Collection** - Gathers all code blocks of the configured language
2. **Concatenation** - Combines blocks with blank-line preservation to maintain
   original line numbers
3. **Analysis** - Runs the external linter on the concatenated code
4. **Mapping** - Maps diagnostics back to exact line/column positions in your
   document

::: {.callout-note}
This approach handles **stateful code** correctly. For example, if an R variable
is defined in one code block and used in another, the linter sees both blocks
together and won't report false "undefined variable" errors.
:::

### Where Linters Run

CLI
:   `panache lint` shows external linter diagnostics

LSP
:   Diagnostics appear inline in your editor as you type

### Behavior

Language matching
:   Code block language (e.g., ```` ```{r} ````) is matched to linter key
    (case-insensitive)

Error handling
:   Missing linters are gracefully ignored with a warning

Timeout
:   30 seconds per linter invocation

Line-accurate
:   Diagnostics report exact line/column locations

Auto-fixes
:   Currently disabled due to byte offset mapping complexity (diagnostics work
    perfectly)

### Example

Enable R linting with jarl while also formatting with air:

```toml
[linters]
r = "jarl"

[formatters]
r = "air"
```

## Example Configuration

Complete example with some common options:

```toml
flavor = "quarto"
line-width = 80

[format]
wrap = "reflow"
blank-lines = "collapse"
math-delimiter-style = "preserve"
math-indent = 0

[extensions]
hard-line-breaks = false
citations = true
task-lists = true

emoji = false

[formatters]
r = "air"
python = "ruff"
```
