Usage
Configuration
Sheath reads its settings from config/sheath.php. You can choose a preset,
set the paths to lint, ignore files, configure individual rules, control
autofixes, and decide how package-aware rules behave.
#Full Configuration
The published config includes the available top-level settings:
<?php
return [
'preset' => 'recommended',
'paths' => [
'resources/views',
],
'ignore' => [
'vendor/**',
'node_modules/**',
'storage/**',
'resources/views/emails/**',
],
'componentMappings' => [
'x-button' => 'button',
'x-navigation.link' => 'a',
],
'rules' => [
'a11y-alt-text' => 'error',
'a11y-html-lang' => ['error', ['default' => 'en']],
],
'baselineLineTolerance' => 3,
'neverFix' => [
// 'best-practices-no-inline-styles',
],
'inlineSuppressions' => true,
'packageRequirementMode' => 'skip',
];
#Presets
A preset gives you a ready-made rule set. Use the rules section to turn
individual rules off, change their severity, or pass options.
| Preset | What it enables | Use it when |
|---|---|---|
recommended |
Defect checks that avoid common ecosystem patterns | Starting with Sheath on most projects |
strict |
recommended plus broader context-sensitive and opinionated checks |
Expanding coverage after reviewing the additional findings |
stylistic |
Formatting and syntax preferences | Enforcing a consistent house style |
migration |
Rewrites from older Blade syntax to current forms | Updating older templates in a dedicated pass |
empty |
No rules | Listing every rule yourself |
'preset' => 'recommended',
'rules' => [
// Turn something off.
'best-practices-no-obsolete-tags' => 'off',
// Or raise it, with options.
'security-no-raw-echo' => ['error', ['allowed' => ['$post->renderedBody']]],
],
#Correctness and style can be combined
stylistic is not a stricter version of recommended; it covers a different
kind of rule. Use both when you want correctness checks and a consistent house
style:
'preset' => ['recommended', 'stylistic'],
Presets apply from left to right, and later presets override earlier ones when
they contain the same rule. strict includes every rule from recommended, so
switching to it does not disable any recommended rules.
#Presets set severities too
Presets choose which rules run and may change the default severity shown on an
individual rule page. Your explicit rules configuration takes precedence over
the preset. Use --print-config to see the resolved severity of every active
rule:
php artisan sheath:lint --print-config
#migration is for a run, not for a config
migration holds rewrites from older Blade syntax to the syntax Laravel
documents today, such as @component to <x-...> and @lang to {{ __() }}.
Nothing in it reports a defect. Run it from the command line when you want to
modernize older templates rather than leaving it in config/sheath.php:
php artisan sheath:lint --preset=migration --dry-run --dangerous
php artisan sheath:lint --preset=migration --fix --dangerous
You must opt in to dangerous fixes because they may change rendered output. See the Blade rules guide for the included rewrites.
--preset replaces the presets from your config, but your individual rules
settings still apply. Use --only when you want to run a specific list
of rules and nothing else.
#The default
If your config omits preset, Sheath uses recommended. Existing projects
therefore pick up rules added to that preset in later Sheath releases. To start
from nothing:
'preset' => 'empty',
The recommended preset covers the default accessibility, security, Blade,
markup, performance, and SEO checks. strict adds checks that are more
context-sensitive, whole-page-oriented, or opinionated. Use --print-config to
see the exact rule set and severities for your current configuration.
#paths
paths defines what Sheath lints when you run php artisan sheath:lint without explicit path arguments.
'paths' => [
'resources/views',
'resources/views/components',
],
Explicit CLI paths override this list and any ignore pattern that would
exclude the entire named path. Without that exception, the shipped
resources/views/emails/** ignore would make this command find nothing:
php artisan sheath:lint resources/views/emails
php artisan sheath:lint --emails
Patterns that exclude something inside the named path still apply, so a generated-file glob is not lost along with the directory-level ignore.
#ignore
ignore is an array of glob-like patterns that are excluded from linting.
'ignore' => [
'vendor/**',
'node_modules/**',
'storage/**',
'resources/views/emails/**',
],
Sheath normalizes patterns against the search path, so project-root paths like resources/views/emails/** still work even when you lint resources/views directly.
See File Patterns for matching details.
#rules
Rules can be configured in two supported formats.
Rule IDs are validated when Sheath starts. Unknown IDs in config/sheath.php, --rule, or --only fail the command instead of being ignored.
#Shorthand
'rules' => [
'a11y-alt-text' => 'error',
'best-practices-button-type' => 'warning',
'seo-meta-description' => 'info',
'blade-no-debug' => 'off',
],
#Long Form
'rules' => [
'a11y-html-lang' => [
'severity' => 'error',
'options' => [
'default' => 'en',
],
],
],
The array shorthand is also supported:
'rules' => [
'a11y-html-lang' => ['error', ['default' => 'en']],
],
#Severity Values
Set each rule to one of these reporting levels.
| Severity | Meaning |
|---|---|
error |
Fails the run |
warning |
Reports the issue but does not fail unless thresholds are used |
info |
Informational |
off |
Disabled |
#Rule Options
Examples of real options supported by built-in rules:
'rules' => [
'a11y-html-lang' => ['error', ['default' => 'en']],
'security-no-inline-js' => ['warning', ['allowed' => ['onclick']]],
'security-csrf-field' => ['error', ['applicationHosts' => ['admin.example']]],
],
Built-in options are validated while configuration is resolved. Unknown option
names, wrong scalar types, non-string list entries, and invalid numeric ranges
throw a configuration error that names the rule and option. List options use
replacement semantics: a configured list replaces the complete default list,
and [] disables that list-based exception or heuristic.
#The universal exclude option
The exclude option is available to every built-in, custom, and package rule.
It accepts a list of path patterns where the rule does not run. The rule still
runs everywhere else, so scoping a
rule to part of the view tree does not cost you its coverage of the rest:
'rules' => [
// The native app's views use framework components with their own
// labelling; the web views still get the full check.
'a11y-form-label' => ['error', ['exclude' => ['views/native/']]],
],
The patterns use the same syntax as the global ignore list. Write them as
project-relative fragments such as views/native/ or **/legacy/**. A leading
slash has no special meaning for rule exclusions. See
File Patterns for the complete syntax.
An excluded rule reports and fixes nothing in matching files. A preset can
supply exclude, your own rules entry can
supply it, and a later entry for the same rule replaces the earlier entry in
full, including exclude. Package authors should prefer this over turning
another package's rule off everywhere. See
Package Presets.
#componentMappings
Blade components do not reveal their rendered HTML element in a template. Add an explicit mapping when a design-system component has one stable native semantic so existing HTML, accessibility, security, SEO, and performance rules can analyze the use site:
'componentMappings' => [
'x-button' => 'button',
'x-navigation.link' => 'a',
'x-avatar' => 'img',
],
Mappings are exact and case-insensitive. The source must be an x- component
tag and the target must be a recognized native HTML element. Dynamic components
cannot be mapped because one call can render different components.
Sheath builds a separate semantic document for non-Blade rules. Blade rules continue to inspect the original component tree, and diagnostics, inline suppression, and fixes are mapped back to the original byte offsets. Native-tag fixes are withheld for the mapped component itself because changing component source as if it were literal HTML is not generally safe; fixes for ordinary HTML elsewhere in the same file remain available.
#baselineLineTolerance
Baselines tolerate small line-number changes. The default tolerance is 3.
'baselineLineTolerance' => 5,
Increase this if your templates move around frequently and baseline matches become too brittle.
#neverFix
neverFix lets you keep a rule enabled but suppress autofix for that rule. Use
documented IDs for built-in rules. A custom rule may also use its own class
name:
'neverFix' => [
'best-practices-no-inline-styles',
'security-no-inline-js',
],
This is useful when you want visibility from a rule but never want automated edits from it in your project.
#inlineSuppressions
Whether sheath-disable comments inside a template are honoured. On by default.
'inlineSuppressions' => true,
Set it to false, or pass --no-inline-config, when a CI or audit run must
report findings even if the template contains suppression comments.
See Inline Suppressions for the comment syntax.
#packageRequirementMode
Some rules can declare Composer package requirements. packageRequirementMode controls how Sheath handles those rules when the package constraint is not satisfied.
'packageRequirementMode' => 'skip',
| Mode | Behavior |
|---|---|
skip |
Do not run rules whose requirements are not met |
disable |
Keep the rule known to Sheath, but inactive because requirements are not met |
ignore |
Ignore package requirements and run the rule anyway |
Sheath never withholds a rule silently. Naming an affected rule under rules,
--rule, or --only warns on every run, and so does a package preset whose
rules are all unavailable, so a preset that contributes nothing cannot pass
as a clean run. --print-config reports the rest: a ruleStatus section, plus
a presetContributions section listing each named package preset's counts and
withheld rule IDs.
ruleStatus contains:
available: rules that can runskippedDueToPackages: known rules excluded by package requirementsdisabledDueToPackages: known rules registered but inactive because package requirements are unmet
Example excerpt:
{
"ruleStatus": {
"available": [
"a11y-alt-text",
"blade-no-debug",
"security-csrf-field"
],
"skippedDueToPackages": {
"custom-livewire-v3-rule": "Unmet requirements: livewire/livewire ^3.0 (not installed)"
},
"disabledDueToPackages": {}
}
}
If a configured package-aware rule appears under skippedDueToPackages or disabledDueToPackages, Sheath warns and does not treat the rule ID as unknown.
#How Configuration Is Validated
Sheath validates config/sheath.php and any --config file before linting.
Unknown top-level keys, wrong value types, malformed rule entries, severity
typos, and unknown rule IDs all fail the run, naming the offending key or rule
rather than falling back to a default. A mistake in your config is therefore a
failed command, never a rule that quietly stopped running.
Two things stay valid: an empty array, which is an explicit request for the defaults, and a missing Laravel config value, which uses them as well.
See Common Error Messages for the individual messages and what each one means.
#CLI Overrides
Configuration can be overridden at runtime:
php artisan sheath:lint --rule=a11y-alt-text:error
php artisan sheath:lint --only=security-csrf-field,blade-no-debug
php artisan sheath:lint --ignore-pattern="resources/views/vendor/**"
php artisan sheath:lint --no-ignore