shuck

Configuration

Shuck can be configured through a shuck.toml or .shuck.toml file.

This page covers Shuck's native configuration for shuck check, shuck format, shuck run, and related native commands. ShellCheck compatibility mode uses .shellcheckrc instead; see the ShellCheck compatibility guide.

Default behavior

If you do not add a config file, Shuck enables all implemented non-style rules by default.

That baseline includes:

  • Correctness rules (C)
  • Performance rules (P)
  • Portability rules (X)
  • Security rules (K)

All style rules are disabled by default, including S074. Shuck also reserves a small internal compatibility exclude list for ShellCheck-style opt-in checks when they map to standalone non-style rules.

You only need a config file when you want to change that baseline.

For example, the following configuration keeps the defaults, adds all style rules, and ignores one specific rule:

[lint]
extend-select = ["S"]
ignore = ["S074"]
fixable = ["ALL"]
unfixable = []

Config file discovery

When Shuck needs configuration for a file or input path, it searches upward from that path for either:

  • .shuck.toml
  • shuck.toml

If both files exist in the same directory, .shuck.toml wins.

Shuck uses the nearest matching config root for each analyzed path. A single invocation can therefore pick up different config files when you lint inputs from different project roots.

Discovered config files do not cascade or merge. Shuck uses the closest config file it finds and ignores parent config files.

Precedence

Configuration is resolved in this order:

  1. --isolated disables discovered config files.
  2. --config path/to/file.toml uses one explicit config file for the entire run.
  3. Otherwise, Shuck discovers the nearest .shuck.toml or shuck.toml for each analyzed path.
  4. Inline overrides passed as --config "<key> = <value>" are applied last.
  5. If you pass the same inline setting more than once, the last one wins.

--isolated cannot be combined with --config path/to/file.toml, but it can still be used with inline overrides.

# Use the nearest discovered config
shuck check .
 
# Use one explicit config file for the whole run
shuck --config ci/shuck.toml check .
 
# Ignore discovered config files and rely only on inline overrides
shuck --isolated --config "lint.select = ['C001']" check .

Check settings

The [check] section controls file-level analysis behavior.

embedded

Enables linting for supported embedded shell scripts in non-shell files such as GitHub Actions workflows and composite actions.

This setting defaults to true.

[check]
embedded = true

Set it to false if you want shuck check to ignore embedded run: blocks and only lint standalone shell files.

See the Embedded Scripts guide for the supported file types and how diagnostics are remapped back to workflow YAML.

Lint settings

Shuck's stable rule-selection config surface lives under [lint].

select

Replaces the default rule set with the selectors you provide.

Selectors can be:

  • A named selector like google
  • A full category prefix like C or K
  • A narrower prefix like C12
  • An exact rule code like S074
  • ALL
[lint]
select = ["google"]

ignore

Removes rules from the currently selected set.

[lint]
select = ["ALL"]
ignore = ["S", "C011"]

extend-select

Adds more rules on top of the current selection.

[lint]
extend-select = ["google"]

per-file-ignores

Defines rule ignores for files matching a glob pattern.

[lint]
extend-select = ["S"]
 
[lint.per-file-ignores]
"scripts/*.sh" = ["S074"]
"testdata/**" = ["ALL"]

extend-per-file-ignores

Adds more per-file ignores on top of any existing per-file-ignores entries.

[lint]
extend-select = ["S"]
extend-per-file-ignores = { "vendor/**" = ["ALL"], "scripts/*.sh" = ["S074"] }

fixable

Restricts which rules are eligible when you run shuck check --fix.

By default, all rules are considered fixable candidates when fixes exist.

[lint]
extend-select = ["S"]
fixable = ["C", "S074"]

unfixable

Marks selected rules as ineligible for automatic fixes, even when --fix is enabled.

[lint]
select = ["ALL"]
unfixable = ["C001"]

extend-fixable

Adds more fixable rules on top of an existing fixable selection.

[lint]
extend-select = ["S"]
fixable = ["C"]
extend-fixable = ["S074"]

Zsh plugin resolution

Shuck's zsh-specific plugin resolution settings live under [lint.zsh.plugins].

Use that section when you want Shuck to resolve real zsh plugin entrypoints for startup files such as .zshrc, especially for oh-my-zsh roots, dynamic plugin lists, and custom plugin entrypoints.

See the dedicated Zsh Support guide for the recommended setup patterns and the Settings Reference for the generated key-by-key reference.

Contracts

Shuck prefers to discover behavior from real sourced files and resolved plugin entrypoints first. Use [lint.contracts] when important runtime or framework behavior cannot be recovered from source alone.

Typical examples include:

  • runtime-provided names that a script reads;
  • plugin settings assigned in .zshrc and consumed later by framework code;
  • metadata assigned in one file and consumed elsewhere by a dispatcher.

See the dedicated Contracts guide for the discovery boundary, examples, and when to prefer Contracts over more source resolution. The Settings Reference includes the exact [lint.contracts] syntax.

Format settings

The formatter reads style options from [format].

[format]
indent-style = "space"
indent-width = 2
binary-next-line = true
switch-case-indent = true
space-redirects = true
keep-padding = true
function-next-line = false
never-split = false

Formatter config follows the same discovery and override rules as the rest of Shuck config. CLI flags passed to shuck format override [format] for that invocation.

Dialect is the exception: [format].dialect is rejected so projects do not accidentally force one parser mode for every file. Use file names, shebangs, or shuck format --dialect ... for a one-off override.

See the dedicated Formatting guide for command examples, stdin behavior, --check, --diff, --simplify, and --minify.

Runtime settings

The [run] section controls managed interpreter defaults for shuck run, shuck install, and shuck shell.

[run]
shell = "bash"
shell-version = "5.2"
 
[run.shells]
bash = "5.2"
zsh = "5.9"

Use [run].shell for a project-wide default interpreter, [run].shell-version for a generic version constraint, and [run.shells] for per-shell pins that apply after Shuck has resolved the script's shell.

See the dedicated Managed Runtime guide for resolution order, inline script metadata, and --system behavior. The generated Settings Reference also includes every supported [run] key.

CLI-only file selection

Some commonly expected settings are command-line flags today, not shuck.toml keys. In particular:

  • --exclude
  • --extend-exclude
  • --respect-gitignore and --no-respect-gitignore
  • --force-exclude and --no-force-exclude

Use those flags directly on shuck check:

shuck check --exclude vendor --extend-exclude fixtures --force-exclude .

Shuck does not currently support configuring those file-selection options in shuck.toml.