Configuration¶
Generate a default .skillsaw.yaml in your repository root:
This creates a config file with all builtin rules, their defaults, and descriptions. Edit it to enable, disable, or customize rules for your project.
Config File Discovery¶
skillsaw looks for a config file starting in the linted directory and walking up the directory tree, all the way to the filesystem root. In each directory it checks, in order:
.skillsaw.yaml.skillsaw.yml.claudelint.yaml(legacy name, still supported).claudelint.yml
The first match wins. Use --config PATH to point at a specific file and
skip discovery entirely. If no config is found, all rules run with their
defaults at the latest version.
Parent configurations are trusted code settings
Discovery continues above the nearest Git repository and can select a
config from a shared workspace or filesystem parent. Such a config can
name Python files under custom-rules. In CI and when inspecting an
unfamiliar checkout, pass --config explicitly and use
--no-custom-rules --no-plugins.
Example Configuration¶
version: "0.10.1"
rules:
content-weak-language:
enabled: auto
severity: warning
content-section-length:
enabled: auto
severity: info
max-tokens: 500
mcp-prohibited:
enabled: false
allowlist: []
exclude:
- "vendor/**"
- "generated/**"
content-paths:
- "docs/runbooks/*.md"
lint-external-content: true
strict: false
fail-on: error
Version Pinning¶
The config file includes a version field set to the skillsaw version that
created it. New rules introduced after that version are automatically skipped
unless you bump the version or explicitly enable them. Repos without a
.skillsaw.yaml run all rules at the latest version — you get new rules
automatically but may occasionally fail after a skillsaw upgrade.
Always set version
A config file without a version field is treated as version
0.6.0. Every rule introduced after 0.6.0 is then silently skipped —
which is most of them. skillsaw prints a warning when it loads such a
config, but the lint still passes, so it is easy to miss. Always set
version to your skillsaw version (skillsaw --version) and bump it
when you upgrade.
Enabling Rules¶
Each rule's enabled key accepts three values:
| Value | Meaning |
|---|---|
true |
Always run the rule, unconditionally |
false |
Never run the rule |
auto |
Run the rule where it applies: when the rule declares repository types, only where those are detected (e.g. plugin rules only run in plugin repos); rules with no such gating run everywhere |
auto also respects the config version gate: a rule newer than the
pinned version stays off until you bump it. enabled: true bypasses
that gate and turns the rule on unconditionally — so prefer auto unless
you deliberately want a rule regardless of version or repo detection.
Most rules default to auto, so they activate only where they make sense.
skillsaw explain <rule-id> shows whether a rule is active in your
repository and why.
Each rule also has a severity, one of error, warning, or info.
By default only errors fail the lint; warnings fail it in
strict mode, and the fail-on
threshold can make any severity — including info — fail the run.
Info-level violations are shown with --verbose (and always when
fail-on: info makes them fatal).
Renamed Rules (Legacy Aliases)¶
0.18.0 renamed the Claude Code format rules to claude- prefixed IDs
(for example plugin-json-valid became claude-plugin-json-valid),
matching how the Codex rules carry a codex- prefix. The old names keep
working everywhere a rule is named — config keys, --rule /
--skip-rule, inline suppression comments, and existing baselines — but
new configs and documentation use the canonical claude- names.
skillsaw explain <legacy-name> resolves the alias and shows the
canonical rule.
Deprecated Rules¶
A deprecated rule no longer runs under enabled: auto and is dropped
from generated configs; it only runs when a config sets enabled: true
(or a --rule flag names it), and doing so emits a warning that the
rule will be removed in a future release. A config entry that merely
mentions a deprecated rule (for example a severity override) also warns,
since the entry has become inert. These deprecation notices are
advisory: they display as warnings but never affect the exit code or
the grade, so upgrading skillsaw cannot break a strict: true CI run
whose config still names a deprecated rule. The Deprecated rules
page lists the current set and replacements.
Strict Mode¶
With strict: true, warnings fail the lint just like errors:
The --strict CLI flag does the same for a single run, overriding the
config file's strict and fail-on settings (see below).
Failure Threshold¶
fail-on generalizes strict mode: violations at the given severity or
above make the run exit non-zero.
fail-on |
Fails the run |
|---|---|
error (default) |
errors only |
warning |
errors and warnings (same as strict: true) |
info |
any violation |
strict: true is shorthand for fail-on: warning. When both config keys
are set, the strictest one wins — adding fail-on: info to a config that
already has strict: true just tightens the threshold.
The --fail-on and --strict CLI flags override the config file's
settings for a single run — --fail-on error runs with the default
threshold even when the config says strict: true. Passing both flags
with contradictory values (--strict --fail-on info) is an error;
--strict --fail-on warning is accepted since they agree.
fail-on: info is useful for ratcheting: once a repo is at zero
violations, it stays that way — new info-level findings (including from
rules added in newer skillsaw versions) fail CI instead of accumulating
silently. When info violations are what failed the run, the text output
shows them even without --verbose. Pair it with a
baseline to adopt the threshold before reaching zero.
skillsaw baseline includes INFO findings with this config setting; when
using only lint --fail-on info, create it with baseline --include-info.
Custom Rules¶
Load project-specific rules from Python files with the custom-rules key.
Relative paths resolve against the config file's directory:
Each file defines one or more Rule subclasses that run alongside the
builtin rules and are configured in the same rules: section by rule ID.
See the Custom Rules guide for how to write them, and
Rule Plugins for sharing rules across repositories as
pip-installable packages.
Exclude Patterns¶
Skip files and directories using glob patterns:
Patterns match against the file path relative to the lint root using
Python fnmatch syntax, where * also crosses /. A leading **/
additionally matches at the root of the repository, so **/templates/**
excludes both a top-level templates/ directory and any nested
a/templates/. A trailing /** matches strictly inside the named
directory: vendor/** excludes vendor/a.md and everything deeper, but
not the vendor entry itself — a violation addressed to the directory,
such as a missing required file, is still reported.
By default, skillsaw excludes **/template/**, **/templates/**,
**/_template/**, and generated Python **/__pycache__/** directories.
These defaults are replaced when you specify your own exclude list.
Exclude patterns apply to all rules, including custom rules loaded via
custom-rules. Any violation whose file path matches an exclude pattern is
filtered out before results are reported. The one exception is
invalid-config: warnings about .skillsaw.yaml itself are never dropped by
exclude patterns (global or per-rule), so an exclude entry matching the
config file cannot silently turn off config validation. To silence a specific
config warning, put a # skillsaw-disable-next-line invalid-config comment
on the line above the flagged one. Only that precise form works for these
warnings: a region # skillsaw-disable, or a bare disable-next-line
naming no rule, does not apply to them.
Rule Options¶
Many rules accept options beyond enabled and severity — each rule's
documentation page lists them, and skillsaw explain <rule-id> prints the
full config template in your terminal for builtin and installed-plugin rules
(project-local custom-rules files are not loaded by explain). Option names come from the rule's
config_schema, so a typo'd or wrong-typed option is reported as an
invalid-config warning. Close matches get a did-you-mean suggestion; type
errors name the expected and actual types. Validation is warn-only: the
configured value still passes through unchanged, except an explicit null
read through Rule.setting() resolves to the schema default. A few rules
additionally check their own values at startup and reject the run with an
error naming the option — warn-only describes the schema validation layer,
not every rule's own checks. An unrecognized
key still counts as configuring the rule and can enable an opt-in rule, so do
not leave the warning unresolved.
The per-rule exclude key must be a list of strings. A malformed value is
ignored by the exclusion filter so it cannot silently disable a rule or crash
the lint. These warnings count toward the grade and fail the run under
--fail-on warning or strict: true; skillsaw baseline is the accepted way
to carry known ones during a migration. invalid-config warnings now point
at the config file and line, which changes their baseline fingerprint — a
baseline recorded on an older skillsaw resurfaces them once, so re-run
skillsaw baseline after upgrading.
Per-Rule Excludes¶
Exclude specific files from a single rule using the exclude key in the
rule's config:
This is useful when a rule produces false positives on specific files but
you still want it enabled globally. Per-rule excludes use the same glob
syntax as global exclude patterns.
Inline Suppression¶
Suppress specific rules on specific lines using comment directives directly in your files. Both HTML comments (for markdown) and hash comments (for YAML) are supported.
Markdown (HTML comments)¶
<!-- skillsaw-disable content-weak-language -->
This section intentionally uses informal language.
<!-- skillsaw-enable content-weak-language -->
Suppress a single line:
Suppress multiple rules at once:
Re-enable all suppressed rules:
Multi-line HTML comments are also supported:
YAML (hash comments)¶
For YAML files (.coderabbit.yaml, promptfooconfig.yaml, etc.), use # comments:
Only full-line # comments are recognized — inline comments like
key: value # skillsaw-disable are ignored.
Note
Inline suppression only affects rules that are already enabled. It cannot be used to enable a normally disabled rule.
Content Paths¶
By default, content intelligence rules only analyze recognized instruction
files (CLAUDE.md, AGENTS.md, .cursor/rules/, .apm/instructions/, etc.).
Use content-paths to extend coverage to any text files that contain
instructions for humans or AI agents — markdown, .mdc, .txt, or any
other format:
Matched files are analyzed by all content-* rules.
External Content¶
lint-external-content is the repository-wide policy for lint-tree nodes
whose provenance is outside the repository's authorship boundary. The first
supported producer is the Vercel skills CLI: skillsaw tags a matching installed
skill as external when its skills-lock.json entry is remote,
package-managed, unknown, or a local source that resolves outside the
repository being linted. Repository-contained local sources remain
repository-owned. APM packages installed under apm_modules/ carry the same
external tag. Other managed formats can adopt it without adding another
configuration key.
External content is linted by default, so malformed or unsafe dependency
content remains visible, but its findings are diagnostic-only:
skillsaw fix never rewrites an externally sourced node. To omit external
payloads from rule discovery entirely, while continuing to validate manifests
and lockfiles owned by the repository itself, set:
This is useful when CI should enforce only content the repository's authors
can change directly. The default is true for backward compatibility and for
teams that want dependency diagnostics.
Rule Plugins¶
Rules from installed rule plugins run automatically. The
plugins key controls which plugins load:
plugins:
enabled: true # default; set false to skip all rule plugins
disable: [acme-rules] # skip specific plugins by name (see `skillsaw plugins`)
plugins: false is accepted as a shorthand for enabled: false. The
--no-plugins CLI flag skips all plugins for a single run. Individual
plugin rules are configured in the normal rules: section by rule ID,
exactly like builtin rules.
For primary findings with different default failure scopes, an explicit rule
severity overrides each scope. For example, antigravity-mcp-valid normally
reports an invalid document as ERROR and a dropped server as WARNING; setting
its severity to INFO lowers both. An omitted or null severity retains the
default classifications. Intentionally separate advisory findings keep the
classification documented by their rule.