Shell module¶
The shell module owns *.sh, *.bash and *.ksh files, plus
extensionless scripts whose shebang names sh, bash, dash or ksh
(#!/bin/sh, #!/usr/bin/env bash, #!/bin/bash -eu). zsh and fish
scripts are not matched, because shellcheck doesn't support them.
| Stage | What runs |
|---|---|
| On edit: auto-fix | shfmt -w on the edited script. shfmt honors .editorconfig (indent style, binary_next_line, switch_case_indent, …). |
| On edit: check | shellcheck -f json1 -S <severity> on the edited script. |
| At Stop: gate | shellcheck over every touched script, then shfmt -l to confirm each one is formatted. |
Issues are reported with shellcheck's rule ids, so Claude can look them up:
[shellcheck] 2 issues
scripts/deploy.sh:14:6 SC2086 Double quote to prevent globbing and word splitting.
scripts/deploy.sh:21:8 SC2050 This expression is constant. Did you forget the $ on a variable?
fix: fix each issue; `# shellcheck disable` comments are not allowed
[format] 1 script not shfmt-formatted
scripts/release
fix: run `shfmt -w` on the files above
New # shellcheck disable=... comments are denied by the
suppression guard, like every other suppression.
Configuration¶
shell:
enabled: true # default: on when shell scripts exist
severity: style # style | info | warning | error — the minimum shellcheck severity reported
shellcheck also reads .shellcheckrc, so repo-wide settings such as
external-sources=true or a default shell=bash apply as usual.
Toolchain¶
| Tool | Required | Missing means |
|---|---|---|
shellcheck |
yes | Edits aren't blocked; the gate fails with a tools check |
shfmt |
yes | Scripts aren't formatted on edit; the gate fails with a tools check |
Both are provisioned automatically: when they aren't on PATH,
Guardrails installs the pinned, checksum-verified versions into its data
directory, in the background at SessionStart. Set tools.install: never
to use only what you've installed, or tools.prefer: managed to always use
the pinned versions. guardrails tools list shows where each tool
resolves from.