---
title: Configuration
---

## Configuration Files

panache searches for configuration in this 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**: `~/.config/panache/config.toml` (XDG)
4. **Built-in defaults**: 80 char width, auto line endings, reflow wrap

## Basic Options

### Flavor

Choose the Markdown flavor, which determines default extension settings:

```toml
flavor = "quarto"
```

**Available flavors:**

- `pandoc` - Standard Pandoc Markdown (default)
- `quarto` - Quarto-flavored Markdown (Pandoc + Quarto extensions)
- `rmarkdown` - R Markdown (Pandoc + R-specific extensions)
- `gfm` - GitHub Flavored Markdown
- `commonmark` - CommonMark (minimal extensions)

### Line Width

Set the maximum line width for wrapping:

```toml
line_width = 80  # Default: 80
```

## Formatting Style

Formatting style preferences are organized under the `[style]` section. This
keeps all style-related settings together.

### Wrapping Mode

Control how text is wrapped:

```toml
[style]
wrap = "reflow"  # Options: "reflow", "preserve"
```

- `reflow` (default): Reformat paragraphs to fit within line width
- `preserve`: Keep existing line breaks

### Blank Lines

Control blank line handling:

```toml
[style]
blank-lines = "collapse"  # Options: "collapse", "preserve"
```

- `collapse` (default): Collapse multiple blank lines into one
- `preserve`: Keep all existing blank lines

### Math Formatting

Configure how math delimiters are formatted:

```toml
[style]
math-delimiter-style = "preserve"  # Options: "preserve", "dollars", "backslash"
math-indent = 0  # Indentation for display math blocks
```

- `preserve` (default): Keep original delimiter style
- `dollars`: Normalize to `$...$` and `$$...$$`
- `backslash`: Normalize to `\(...\)` and `\[...\]`

### Code Block Style

Configure code block formatting preferences:

```toml
[style.code-blocks]
fence-style = "backtick"       # Options: "backtick", "tilde", "preserve"
attribute-style = "shortcut"   # Options: "shortcut", "explicit", "preserve"
min-fence-length = 3           # Minimum fence length (default: 3)
normalize-indented = false     # Convert indented code to fenced blocks (default: false)
```

**Fence style:**

- `backtick`: Use `` ``` `` fences
- `tilde`: Use `~~~` fences
- `preserve` (default for Pandoc): Keep original fence style

**Attribute style:**

- `shortcut` (default for Quarto/RMarkdown): `` ```python ``
- `explicit`: `` ```{.python} ``
- `preserve` (default for Pandoc): Keep original style

**Note:** These defaults vary by flavor. Quarto uses `backtick` and `shortcut`,
while Pandoc preserves original formatting.

### Backwards Compatibility

For backwards compatibility, style options can still be specified at the
top-level (deprecated):

```toml
# OLD FORMAT (deprecated, but still works)
wrap = "reflow"
blank-lines = "collapse"

# NEW FORMAT (preferred)
[style]
wrap = "reflow"
blank-lines = "collapse"
```

If both formats are present, the `[style]` section takes precedence. A warning
will be logged when using the deprecated top-level format.

## Extensions

panache supports 60+ Pandoc extensions. Each flavor has sensible defaults, but
you can override any extension:

```toml
flavor = "quarto"

[extensions]
# Override flavor defaults
hard_line_breaks = false
citations = true
task_lists = true
```

### Block-Level Extensions

#### Headings

```toml
[extensions]
blank_before_header = true       # Require blank line before headers
header_attributes = true         # {#id .class key=value} syntax
```

#### Block Quotes

```toml
[extensions]
blank_before_blockquote = true   # Require blank line before blockquotes
```

#### Lists

```toml
[extensions]
fancy_lists = true               # Roman numerals, letters
startnum = true                  # Start at arbitrary numbers
example_lists = true             # (@) example markers
task_lists = true                # - [ ] and - [x]
definition_lists = true          # Term/definition syntax
```

#### Code Blocks

````toml
[extensions]
backtick_code_blocks = true      # ``` fences
fenced_code_blocks = true        # ~~~ fences
fenced_code_attributes = true    # {.language #id}
inline_code_attributes = true    # `code`{.class}
````

#### Tables

```toml
[extensions]
simple_tables = true             # Simple table syntax
multiline_tables = true          # Multiline cells
grid_tables = true               # Grid-style tables
pipe_tables = true               # GitHub-style | tables
table_captions = true            # Table captions
```

#### Divs

```toml
[extensions]
fenced_divs = true               # ::: {.class} divs
native_divs = true               # HTML <div> elements
```

### Inline Extensions

#### Emphasis

```toml
[extensions]
intraword_underscores = true     # Don't trigger emphasis in snake_case
strikeout = true                 # ~~strikethrough~~
superscript = true               # ^super^
subscript = true                 # ~sub~
```

#### Links

```toml
[extensions]
inline_links = true              # [text](url)
reference_links = true           # [text][ref]
shortcut_reference_links = true  # [ref]
link_attributes = true           # [text](url){.class}
autolinks = true                 # <http://example.com>
autolink_bare_uris = false       # Bare URLs → links (non-default)
```

#### Images

```toml
[extensions]
inline_images = true             # ![alt](url)
implicit_figures = true          # Single image → figure
```

#### Math

```toml
[extensions]
tex_math_dollars = true          # $x$ and $$equation$$
tex_math_single_backslash = false  # \(...\) and \[...\] (RMarkdown)
tex_math_double_backslash = false  # \\(...\\) and \\[...\\]
```

#### Footnotes

```toml
[extensions]
inline_footnotes = true          # ^[text]
footnotes = true                 # [^1] references
```

#### Citations

```toml
[extensions]
citations = true                 # [@cite] syntax
```

#### Spans

```toml
[extensions]
bracketed_spans = true           # [text]{.class}
native_spans = true              # HTML <span> elements
```

### Metadata Extensions

```toml
[extensions]
yaml_metadata_block = true       # --- YAML frontmatter
pandoc_title_block = true        # % Title / % Author / % Date
```

### Raw Content Extensions

```toml
[extensions]
raw_html = true                  # HTML blocks and inline
markdown_in_html_blocks = true   # Markdown inside HTML
raw_tex = true                   # LaTeX commands
raw_attribute = true             # {=format} raw blocks
```

### Special Character Extensions

```toml
[extensions]
all_symbols_escapable = true     # Backslash escapes any symbol
escaped_line_breaks = true       # Backslash at line end = <br>
hard_line_breaks = false         # Newline = <br> (non-default)
emoji = false                    # :emoji: syntax (non-default)
mark = false                     # ==highlighted== (non-default)
```

### Quarto-Specific Extensions

```toml
[extensions]
quarto_callouts = true           # .callout-note, etc.
quarto_crossrefs = true          # @fig-id, @tbl-id
```

## External Code Formatters

panache can invoke external formatters for code blocks—**but they're opt-in**.
You choose what gets formatted.

### Basic Usage

Map languages to formatters using built-in presets:

```toml
[formatters]
r = "air"           # Single formatter
python = "ruff"     # Single formatter
javascript = "prettier"
typescript = "prettier"  # Reuse same formatter
```

**Available presets:**

| Language | Preset     | Command                    | Notes                      |
| -------- | ---------- | -------------------------- | -------------------------- |
| `r`      | `air`      | `air format {}`            | Fast, modern               |
| `r`      | `styler`   | `Rscript -e "styler::..."` | Requires styler R package  |
| `python` | `ruff`     | `ruff format`              | Fast, modern               |
| `python` | `black`    | `black -`                  | Popular alternative        |
| `yaml`   | `yamlfmt`  | `yamlfmt -`                | YAML formatter             |
| `yaml`   | `prettier` | `prettier --parser=yaml`   | Alternative YAML formatter |

### Sequential Formatting

Run multiple formatters in order by using an array:

```toml
[formatters]
python = ["isort", "black"]  # isort first, then 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"

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

# Custom formatter not in presets
[formatters.isort]
cmd = "isort"
args = ["-"]
stdin = true  # Default
```

**Formatter definition fields:**

- `cmd`: Command to execute (required for custom formatters)
- `args`: Command-line arguments (optional, defaults to `[]`)
- `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"

# Partial override - only customize args
[formatters.air]
args = ["format", "--preset=tidyverse"]
# cmd and stdin are inherited from built-in "air" preset
```

**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:**

```toml
# Override only args (inherits cmd="air", stdin=false)
[formatters.air]
args = ["format", "--custom-flag", "{}"]

# Override only cmd (inherits args=["format"], stdin=true)
[formatters.ruff]
cmd = "ruff-custom"

# Override everything (complete replacement)
[formatters.black]
cmd = "my-black"
args = ["--fast"]
stdin = false
```

### Incremental Argument Modification

Instead of completely overriding `args`, you can add arguments incrementally
using `append_args` and `prepend_args`:

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

# Add arguments to preset's base args
[formatters.air]
# Base args from preset: ["format", "{}"]
append_args = ["-i", "2"]
# Final args: ["format", "{}", "-i", "2"]
```

**Field descriptions:**

- `prepend_args`: Arguments added **before** base args
- `append_args`: Arguments added **after** base args
- Base args come from either the preset or explicit `args` field

**Multiple modifiers:**

```toml
[formatters.air]
prepend_args = ["--verbose"]
append_args = ["-i", "2", "--check"]
# Final: ["--verbose", "format", "{}", "-i", "2", "--check"]
```

**With explicit args (no preset):**

Modifiers work with custom formatters too:

```toml
[formatters.shfmt]
cmd = "shfmt"
args = ["-filename", "$FILENAME"]
append_args = ["-i", "2", "-bn"]
# Final: ["-filename", "$FILENAME", "-i", "2", "-bn"]
```

**Both modifiers together:**

```toml
[formatters.custom]
cmd = "formatter"
args = ["--input"]
prepend_args = ["--config", "cfg.toml"]
append_args = ["--output", "result.txt"]
# Final: ["--config", "cfg.toml", "--input", "--output", "result.txt"]
```

### File-Based Formatters

For formatters that modify files in place:

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

[formatters.air-file]
cmd = "air"
args = ["format", "{}"]  # {} = file path placeholder
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)
- Formatters respect their own config files (`.prettierrc`, `pyproject.toml`,
  etc.)

### Supported Formatters

Any CLI tool that reads stdin and writes stdout works:

- **R**: `air`, `styler`, `formatR`
- **Python**: `black`, `ruff format`, `autopep8`, `isort`
- **Rust**: `rustfmt`
- **JavaScript/TypeScript**: `prettier`, `deno fmt`
- **JSON**: `jq`, `prettier`
- **YAML**: `yamlfmt`, `prettier`
- **Go**: `gofmt`
- **SQL**: `sqlformat`, `pg_format`

## External Code Linters

panache can invoke external linters for code blocks—**but they're opt-in**. You
choose which languages to lint.

### Quick Start

Enable linters for specific languages:

```toml
# Enable R linting with jarl
[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

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
- **Limitations**: Auto-fixes from external linters are currently disabled due
  to byte offset mapping complexity. Diagnostics work perfectly.

### Example

```toml
# .panache.toml
[linters]
r = "jarl"

# Still enable R formatting separately
[formatters.r]
preset = "air"
```

## Example Configuration

Complete example with all common options:

```toml
# Markdown flavor and basic settings
flavor = "quarto"
line_width = 80

# Formatting style (NEW: organized under [style] section)
[style]
wrap = "reflow"
blank-lines = "collapse"
math-delimiter-style = "preserve"
math-indent = 0

[style.code-blocks]
fence-style = "backtick"
attribute-style = "shortcut"

# Extension overrides
[extensions]
hard_line_breaks = false
citations = true
task_lists = true
emoji = false

# External formatters (opt-in)
[formatters]
python = ["isort", "black"]  # Sequential: isort then black
r = "air"                    # Built-in preset
javascript = "prettier"      # Reusable definition
typescript = "prettier"
rust = "rustfmt"

# Customize formatters (optional)
[formatters.prettier]
args = ["--print-width=100"]

[formatters.isort]
cmd = "isort"
args = ["-"]

# External linters (opt-in)
[linters]
r = "jarl"  # Enable R linting
```

## See Also

- [CLI Reference](cli.qmd) - Using `--config` flag
- [Formatting](formatting.qmd) - How configuration affects output
- [Getting Started](getting-started.qmd) - Basic configuration examples
