116 rules, zero model calls
Every finding in a paniolo scan report comes from a deterministic
rule that runs locally — the same tree always gets the same score. Rules are
grouped by the dimension they score into; each carries a default severity you
can override per repo.
How a rule runs
| Surface | Behavior |
|---|---|
| Severity | error fails --fail-on error; warn reports without failing the default gate; info is advisory. Any rule can be retuned — or set to off — in rules. |
| Per-run overrides | --rule <id>=<severity> tunes one rule for the invocation; --profile selects a built-in rule profile; --harness restricts to one vendor's surface. |
| Applicability | Most rules always run. Some only apply to intelligence-layer source repos, and one family does network I/O — those only run under the opt-in --external-links flag, never in the default offline scan. |
| Custom rules | customRules declares repo-local rules that join the registry — scored and tuned like a built-in. |
| Unknown ids | --strict-config fails the scan when the config names a rule that doesn't exist — a stale id fails loudly instead of silently doing nothing. |
Flag-by-flag detail lives in the scan guide; the config fields are in the config reference.
Every built-in rule
Generated from the rule registry in @paniolo/cli —
regenerate with node scripts/gen-rules-doc.mjs.
Where a rule says "Oxc-backed", it runs on parsed TypeScript, not text matching.
Guardrails 58 rules
Security, permissions, CI hygiene, and the probabilistic/deterministic boundary.
| Rule | Severity | What it checks |
|---|---|---|
actions-sha-pinned | warn | flags workflow actions pinned to mutable tags instead of commit SHAs. |
agent-resource-budget-caps | info | flags an agent/tool surface with no declared resource caps (max iterations, cost, or rate limit). |
boundary.no-assert-mocked-return | warn | Oxc-backed boundary rule for mock-return assertions in test files. |
boundary.no-cross-package-deep-import | warn | Oxc-backed boundary rule for workspace cross-package import shape. |
boundary.no-disable-in-tests | warn | Oxc-backed boundary rule for lint-disable comments in test files. |
boundary.no-dual-named-and-default-export | warn | Oxc-backed boundary rule for the one-canonical-export-path convention. |
boundary.no-empty-arrange | warn | Oxc-backed boundary rule for empty // Arrange comments in test files. |
boundary.no-module-load-only-test | warn | Oxc-backed boundary rule for import-success-only unit tests. |
boundary.no-reactelement-import | warn | Oxc-backed boundary rule for the ReactElement ambient-type convention. |
boundary.no-runtime-test-for-type-only-module | warn | Boundary rule for runtime tests conventionally paired with type-only modules. |
boundary.no-tautological-assertion | warn | Oxc-backed boundary rule for assertions that prove only their own literals. |
boundary.no-test-for-constants-only-module | warn | Boundary rule for tests conventionally paired with constants-only modules. |
boundary.no-test-of-test-utility | warn | Boundary rule for dedicated tests of test-only infrastructure. |
boundary.no-void-async-iife | warn | Oxc-backed boundary rule banning void <async fn>() fire-and-forget invocations, ported from the ESLint no-restricted-syntax selector UnaryExpression[operator='void'] > CallExpression[callee.async=true]. |
boundary.require-aaa-pattern | warn | Oxc-backed boundary rule requiring Arrange/Act/Assert comments in tests. |
boundary.require-each-type-param | warn | Oxc-backed boundary rule requiring a TypeScript type parameter on it.each, test.each, and describe.each calls. |
boundary.require-own-file-for-long-function | warn | Oxc-backed boundary rule for module-scope function file splits. |
boundary.require-useeffect-comment | warn | Oxc-backed boundary rule requiring a comment above every useEffect. |
ci-enforcement-gates | info | flags repos whose CI workflows never run a typecheck/lint/static-analysis gate. |
ci-guidance-lint | info | flags repos whose CI never runs a guidance-maintenance gate (markdown lint, link check, self-scan). |
ci-validation-gates | info | flags repos whose CI workflows never run a test command. |
claude-hooks-valid | error | validates .claude/settings*.json hook shape and script references. |
codex-agents-valid | error | checks that every .codex/agents/*.toml thin wrapper stays consistent with its shared .agents/agents/*.agent.md definition, and that every shared agent has a wrapper. |
codex-hook-counts | error | checks that .codex/hooks.json wires the committed number of hooks per event group, so a refactor cannot silently drop the qmd prompt-context, maintenance, or stop hooks. |
codex-hooks-valid | error | validates .codex/hooks.json shape and script references. |
comment-obvious-name-repeat | info | flags symbol comments whose first sentence only restates the symbol name and kind. |
correction-loop-documented | info | flags repos with no durable AI correction-loop signal across scripts, PR templates, or CI. |
cursor-hook-counts | error | checks that .cursor/hooks.json wires the committed number of native handlers per event, so a refactor cannot silently drop the session guidance, shell guard, edit tracking, or stop lint gate. |
custom-diagnostics-present | info | flags repos with no repo-specific lint/static-analysis rules beyond a generic lint gate. |
editor-hooks-valid | error | validates .github/hooks/*.json (VS Code custom-agent format) and .cursor/hooks.json (Cursor native format): each must be valid JSON, and every scripts/….ts path referenced by a hook command must exist on disk. |
env-files-gitignored | warn | flags committed .env* files unless they're gitignored. |
escalation-protocol-discoverability | info | flags guidance that documents no epistemic-escalation protocol (asking for clarification on missing, ambiguous, or contradictory specs). |
focused-test-commands-present | info | flags repos with no discoverable narrower validation command than the full suite. |
high-impact-action-confirmation | warn | flags source that performs high-impact actions (deletion, payment, force-push, deploy, external send) with no human-in-the-loop confirmation or escalation in evidence. |
hook-launcher-portable | error | checks that committed hook configs do not name a platform-specific launcher path. |
hook-no-network-exfil | error | flags hook scripts that make a network call to a non-local host. |
hook-stop-circuit-breaker | warn | flags Stop hooks that never check stop_hook_active before re-blocking. |
jsdoc-enforcement-present | info | flags repos where JSDoc comment standards are not documented and enforced deterministically. |
jsdoc-no-typescript-types | warn | JSDoc comment policy rules over shared code-symbol records. |
jsdoc-spacing | warn | flags a JSDoc block whose preceding line breaks the repository's comment-spacing convention. |
lint-gate-present | info | flags repos with no discoverable lint/static-analysis gate. |
llm-output-schema-validated | warn | flags source files that consume LLM/tool output without a schema validator in scope. |
memory-write-provenance | info | flags a persistent-memory-write surface with no provenance/trust tagging or re-validation in evidence. |
model-interface-pinned | warn | flags floating -latest model-id aliases in application source/config. |
no-dangerous-auto-approve | error | flags .claude/settings*.json files that set a bypass defaultMode or auto-approve a dangerous tool with a blanket allow entry. |
no-pull-request-target | error | flags workflows triggered by pull_request_target, which runs with repo secrets against untrusted PR code. |
paniolo-state-gitignored | warn | flags a present .paniolo/ that no ignore pattern covers. |
rustdoc-public-items | warn | Rustdoc comment policy rules over shared code-symbol records. |
secret-scanning-configured | warn | flags repos with no detectable secret-scanning configuration. |
sensitive-strings | warn | flags lines containing sensitive strings that must not be committed, such as hardcoded home-directory paths that leak a username. |
skill-destructive-verb-confirmation | info | flags skills/**/SKILL.md files that instruct a destructive action without a nearby confirmation / staging / dry-run cue in the same markdown section. |
skill-side-effect-disclosure | info | flags skills/**/SKILL.md files whose body describes state mutations (writing files, committing, pushing, mutating config) while the frontmatter description: gives no hint that the skill leaves state behind. |
strict-typecheck-present | info | flags repos with no discoverable strict typecheck/static-analysis gate. |
test-gates-present | info | flags repos with no discoverable unit/integration/E2E validation gate. |
tool-allowlist-inventory | info | flags a repo that references MCP/tool servers but declares no explicit, pinned tool allowlist. |
tool-contract-tests-present | info | flags a repo that declares model-callable tools but whose tests never exercise tool-call argument validation or error responses. |
untrusted-input-action-boundary | warn | flags source that both ingests untrusted content and takes actions with no sanitization, validation, or confirmation in evidence. |
vscode-custom-hooks | warn | warns when .github/hooks/ exists but chat.useCustomAgentHooks isn't enabled in .vscode/settings.json. |
Maintainability 27 rules
Size budgets, structure, duplication, and upkeep of guidance files.
| Rule | Severity | What it checks |
|---|---|---|
agent-frontmatter | error | flags agents/**/*.agent.md files missing YAML frontmatter or the required name/description fields. |
agent-line-count | warn | warns when an agents/**/*.agent.md file exceeds the line budget. |
code-layout | warn | flags flat module sprawl and junk-drawer feature folder names so the legacy harness check-code-layout script can move into scan. |
dead-code | warn | Rust-native project graph analysis for JavaScript and TypeScript, backed by Fallow. |
doc-fragment-links | warn | flags outbound path.md#anchor fragment links in AI-context files. |
emphasis-keyword-density | info | flags instruction files that lean on all-caps emphasis keywords. |
external-links-resolve | warn | opt-in **network** rule flagging dead external http(s) URLs in the guidance corpus. |
github-skills-shadow | warn | forbidden-legacy-paths — flags markdown references to known-removed or shadow guidance paths (e.g. |
guidance-links-resolve | warn | flags internal markdown links in guidance files whose target does not resolve. |
guidance-maintenance-script | info | flags repos with detectable project context but no discoverable guidance-maintenance script (e.g. |
identity-language-absent | info | flags instruction files that contain identity / roleplay filler the model would follow anyway. |
link-fragments-resolve | warn | flags markdown links whose #fragment does not resolve to a heading or explicit <a id> anchor in the target file. |
local-context-patterns | info | flags repos with detectable guidance or memory context but no documented local-context conventions (naming and comment conventions, or nested AGENTS.md files). |
no-duplicate-agent-trees | error | flags duplicate or legacy agent trees: - .github/agents/ when a canonical agents/ or .agents/agents/ tree exists - agents/ root when .agents/agents/ is the canonical location (June 2026 layout) |
no-file-scheme-links | warn | flags markdown links whose href uses a file: scheme (for example the VS Code file URIs that AI tools sometimes emit). |
no-heading-anchors | warn | flags standalone HTML heading anchors (<a id="…"></a> alone on a line) in skills and the shared rules file. |
pr-template-ai-harness-check | info | flags repos with detectable project context but no PR template reminder to update durable AI harness assets (rules, docs, skills, tests, diagnostics). |
rust-first-harness-boundary | warn | keeps Rust-first harness repos from growing legacy TypeScript/JavaScript product surfaces without making the current retirement backlog noisy. |
skill-count | info | a sanity-ceiling smell test for runaway skill-library growth. |
skill-description-budget | warn | flags skills/**/SKILL.md frontmatter whose combined description + when_to_use text is near or over Claude Code's 1,536-character listing cap. |
skill-fallback-guidance | info | flags skills/**/SKILL.md files that name an external dependency (a CLI, MCP server, binary, or another tool) without any guidance on what to do when that dependency is missing or fails. |
skill-invocation-gate-consistency | info | flags skills/**/SKILL.md files whose invocation gates (disable-model-invocation, user-invocable) look inconsistent with whether the body reads as a task or as reference material. |
skill-line-count | warn | warns when a skills/**/SKILL.md file exceeds the line budget. |
skill-missing-do-not | info | flags skills/**/SKILL.md files that lack a ## Do Not section. |
skill-missing-references | info | flags skills/**/SKILL.md files that lack a ## References section. |
wiki-authoring-links-resolve | warn | flags AI-context links to a configured wiki page (<wiki>/wiki/<slug>.md) whose target file does not exist on disk. |
wiki-link-style | warn | flags markdown references to a configured wiki page by raw path (<wiki>/wiki/<slug>.md) that should instead use wikilink ([[slug]]) syntax, so the reference participates in the wiki graph. |
Discoverability 12 rules
Whether agents can find what exists — indexes, mentions, registration.
| Rule | Severity | What it checks |
|---|---|---|
agents-md-mentions-skills | info | flags AGENTS.md with no pointer to skill discovery when root skills/ is non-empty. |
claude-agent-routing | info | flags CLAUDE.md with no Agent Routing table when Claude is detected. |
memory-docs-indexed | info | flags durable memory docs with no index and no search surface. |
qmd-script-present | info | flags repos with skills/ or 2+ .agents/ files and no qmd (or equivalent) doc-search script. |
skill-boundary-language | info | flags complex skills/**/SKILL.md files that lack routing exclusion language. |
skill-composition-discoverability | info | warns when a repo has several skills but cross-references between them are rare, suggesting a flat/monolithic skill set with no widely-declared composition structure. |
skill-dependency-declaration | info | flags skills/**/SKILL.md files whose body contains ordering/prerequisite language without declaring the dependency structurally (a dependsOn:-style frontmatter field or a ## Use When section). |
skill-description-overlap | info | flags pairs of skills/**/SKILL.md files whose frontmatter description: fields are near-duplicates under token Jaccard similarity. |
skill-doc-deep-links | info | flags substantial skills/**/SKILL.md files that inline detail instead of deep-linking into durable guidance under .agents/, docs/, or wiki/ (llm-wiki). |
skill-index-orphans | info | flags root skills that are not mentioned in the skill slug index. |
skill-self-contained | error | shipped paniolo-* skills must contain no [[wikilink]] syntax. |
skills-index | info | flags a non-empty root skills/ with no skill slug index. |
Layering 7 rules
What loads always vs on demand — context budget discipline.
| Rule | Severity | What it checks |
|---|---|---|
adapter-line-count | warn | warns when any root adapter file (CLAUDE.md, GEMINI.md, .github/copilot-instructions.md, DEVIN.md, etc.) exceeds the line budget. |
adapter-points-to-shared | warn | warns when a present root adapter (CLAUDE.md, GEMINI.md, .github/copilot-instructions.md) doesn't reference shared AGENTS.md or canonical rules layers. |
agents-md-line-count | warn | warns when AGENTS.md exceeds the line budget. |
no-duplicate-skill-trees | error | flags alternate skill trees that duplicate the canonical .agents/skills/ tree. |
rules-doc-line-count | warn | warns when the shared .agents/rules.md exceeds the line budget. |
shared-agents-md | warn | warns when AGENTS.md is missing. |
shared-rules-doc | warn | warns when no canonical rules doc is present. |
Reliability 4 rules
Contracts, tests, and pinning that keep agent behavior predictable.
| Rule | Severity | What it checks |
|---|---|---|
skill-eval-artifact-completeness | warn | flags skills/**/SKILL.md trees that advertise an evals/ harness (skill-creator / agentskills.io convention) but ship a missing, invalid, empty, or fixture-broken evals/evals.json. |
skill-frontmatter | error | flags skills/**/SKILL.md files missing YAML frontmatter or the required name/description fields. |
skill-frontmatter-yaml | error | flags skills/**/SKILL.md frontmatter blocks that fail to parse as YAML, parse to a non-mapping value, or have a name/description field of the wrong type. |
skill-link-integrity | error | flags skill-to-skill markdown links whose target SKILL.md path does not exist in the repo. |
Sharing 3 rules
One source of truth, wired into each adapter — not copied into each.
| Rule | Severity | What it checks |
|---|---|---|
adapter-content-duplication | warn | flags root adapter text that duplicates blocks from the canonical .agents/rules.md. |
adapter-context-budget | info | flags always-loaded instruction files that exceed the per-file line budget. |
always-loaded-budget | info | flags detected harnesses whose total always-loaded context exceeds the recommended line budget. |
Harness wiring 3 rules
Vendor-specific plumbing — hooks, adapter locations, per-tool config.
| Rule | Severity | What it checks |
|---|---|---|
devin-config-present | warn | warns when Devin CLI is detected but .devin/config.json is absent or does not set read_config_from.claude: true. |
vscode-agents-location | warn | warns when .vscode/settings.json doesn't configure chat.agentFilesLocations to point at agents/ or .agents/agents/ (the consolidated layout introduced June 2026). |
vscode-skills-location | warn | warns when .vscode/settings.json doesn't configure chat.agentSkillsLocations to point at the configured skills directory. |
Consistency 1 rule
Same meaning, same shape, everywhere it appears.
| Rule | Severity | What it checks |
|---|---|---|
skill-link-style | warn | enforces one configured link style for skill-to-skill references inside SKILL.md files. |
Readability 1 rule
Prose quality of the guidance itself.
| Rule | Severity | What it checks |
|---|---|---|
skill-max-line-length | warn | flags prose lines in skills/**/SKILL.md files that exceed a configurable character budget. |