forcedotcom/sf-skills/dx-code-analyzer-custom-rule-create
Claude Code and agent skill by forcedotcom/sf-skills
- community
- ext:[{"type":"plugin","description":"Custom plugin integration"}]
Checking that the SKILL.md file is still in the repository.
Create custom Code Analyzer rules for Regex (pattern matching), PMD (XPath/AST for Apex and metadata XML), and ESLint (LWC/JavaScript/TypeScript). Use when users want to enforce coding standards, ban patterns, detect hardcoded values, govern metadata, or add rules not in the built-in set. TRIGGER when: user says 'create a rule', 'ban System.debug', 'enforce naming convention', 'detect hardcoded IDs', 'custom rule', 'xpath rule', 'regex rule', 'add a PMD rule', 'enforce a policy', 'create a check for', 'flag this pattern', 'make a rule that catches', 'metadata rule', 'check permissions', 'enforce API version', 'eslint rule', 'lwc rule', 'override rule threshold', 'customize complexity', or describes a pattern to enforce. DO NOT TRIGGER when: user wants to run a scan (use dx-code-analyzer-run), configure engines (use dx-code-analyzer-configure), or explain existing rules (use dx-code-analyzer-run).
Install
npx vskill@latest install forcedotcom/sf-skills/dx-code-analyzer-custom-rule-createSemi-extensibleMentions customization, but needs skill-specific knowledge. Read the extensible skills standard
SKILL.md
dx-code-analyzer-custom-rule-create: Custom Code Analyzer Rule Authoring
Ecosystem: This skill is part of a 3-skill Code Analyzer suite —dx-code-analyzer-run(scans & results) ·dx-code-analyzer-configure(setup, config, CI/CD) ·dx-code-analyzer-custom-rule-create(custom rule authoring).
Use this skill when the user needs to create a custom rule that enforces a pattern not covered by Code Analyzer's built-in rules. Supports Regex engine (text pattern matching) and PMD engine (structural XPath queries against the AST).
When This Skill Owns the Task
Use dx-code-analyzer-custom-rule-create when the work involves:
- Creating a new custom rule for Code Analyzer (any engine)
- Enforcing team-specific coding standards via static analysis
- Banning specific patterns (System.debug, hardcoded IDs, TODOs)
- Writing XPath expressions for PMD rules (Apex or metadata XML)
- Writing regex patterns for the Regex engine
- Setting up custom ESLint rules/plugins for LWC/JavaScript
- Enforcing metadata governance (API versions, field descriptions, dangerous permissions)
- Overriding built-in rule thresholds (CyclomaticComplexity, ExcessiveParameterList, etc.)
- Organizing multiple rules into shared rulesets
- Iterating on a custom rule that isn't matching correctly
Delegate elsewhere when the user is:
- Running a scan against existing rules →
dx-code-analyzer-runskill - Configuring engines, prerequisites, CI/CD →
dx-code-analyzer-configureskill - Explaining what an existing built-in rule means →
dx-code-analyzer-runskill - Writing Apex code or tests →
generating-apex/running-apex-testsskills
Required Context to Gather First
Ask for or infer:
- What pattern to catch — what code should be flagged? (If user selected code in their IDE, the selection IS the answer — do not re-ask.)
- What to allow — any exceptions? (test classes, specific contexts)
- File scope — which file types? (.cls, .trigger, .js, all?)
- Severity — how critical? (default: 3/Moderate)
If the user selected code (IDE selection context present), treat it as the pattern definition. Skip clarification unless genuinely ambiguous about what aspect of the selection to target.
If the request is vague with NO selection ("add a rule for best practices"), ask ONE clarifying question:
"What specific pattern should this rule flag?"
Hard Constraints
These are non-negotiable rules. Violating any of them is a skill failure regardless of whether the output happens to work.
- ALWAYS run `ast-dump` before writing XPath. No exceptions. Do not use node names from memory, references, or prior conversations. The AST is the source of truth — run
sf code-analyzer ast-dump, read the output, then write XPath that matches what you see. Even for "well-known" patterns like SOQL-in-loop, run ast-dump first. If you skip this step and the rule works, it is still a process failure.
- ALWAYS use the scripts to create rules. For regex rules, ALWAYS use
create-regex-rule.js. For PMD rules, ALWAYS usecreate-pmd-rule.js. Do NOT manually editcode-analyzer.ymlto add rule definitions — regex patterns in YAML cause escaping failures (quotes inside quotes, backslashes getting eaten). The scripts handle YAML serialization correctly every time.
- NEVER manually edit `code-analyzer.yml` after a script writes to it — even to fix a bad value. The scripts produce correctly-escaped YAML. If you then rewrite or restructure the file, you WILL break the escaping. If the user added top-level config (like
ignores.files), leave it alone too — only touch what you wrote.
If a script's output looks wrong (rule fails to validate, YAML parse error, stray characters in the regex):
- DO NOT patch the YAML by hand. That is exactly the failure mode this constraint exists to prevent.
- Always delete the broken rule's entire YAML block, then re-invoke the script with corrected arguments. Removing a block you just wrote does not violate this rule; rewriting fields inside it does.
- If the script accepted bad input and produced bad output, the input was wrong (e.g.,
--regex "/.../ g"with a stray space — the flags must be/gexactly, no whitespace). Re-invoke with the corrected argument. - If you genuinely believe the script has a bug, STOP and surface it to the user. Do not hand-edit as a workaround.
- `--regex` must be `/pattern/flags` with NO whitespace. The script trims and validates flags strictly — only
g,i,m,s,u,y./pat/ g(with a space) is rejected; so is/pat/x(invalid flag) and/pat/(no flags). The global flaggis mandatory. If validation fails, fix the argument — do NOT bypass by writing YAML directly.
- ALWAYS validate after creation. Run
sf code-analyzer rules --rule-selector <engine>:<name>before testing. IfFound 0 rules, the YAML didn't parse — delete the block, fix the argument, re-invoke the script.
- ALWAYS test against a sample file. Confirm at least one true positive and one true negative.
For regex rules, the negative sample MUST NOT contain the pattern text anywhere — including inside comments and string literals. Regex engines scan raw text; // no System.debug here IS a match for /System\.debug/g. Trace your pattern against the negative file mentally before running it.
- Create rules ONE AT A TIME, sequentially. When the user requests multiple rules, create each rule individually through the full workflow (create → validate → test positive → test negative) before starting the next one. Do NOT batch-create rules — if one fails, it corrupts the config for all subsequent rules. Complete each rule end-to-end, confirm it works, then move to the next.
- For regex rules, exclude test classes via `ignores.files` — `regex_ignore` does NOT do this.
regex_ignoreis a per-LINE filter (the line must match BOTH the rule and the ignore pattern); it cannot exclude an entire test class. If the user's intent is "skip test classes," add a top-levelignores.filesblock with globs like"**/*Test.cls"AFTER all rules are created — do not interleave config edits with script invocations.
Engine Selection
| Pattern Type | Engine | Why | |
|---|---|---|---|
| Text/string pattern (TODO, hardcoded ID, keyword) | Regex | Simple, fast, no Java needed | |
| Apex code structure (method calls, nesting, SOQL in loops) | PMD/XPath (language=apex) | Understands AST, not fooled by comments/strings | |
| Metadata XML governance (API version, permissions, descriptions) | PMD/XPath (language=xml) | Structural XML matching with namespace handling | |
| LWC/JavaScript/TypeScript patterns | ESLint* | Standard JS tooling, plugin ecosystem | |
| Both could work (Apex/metadata only) | Regex first | Simpler to create and maintain |
\* For ESLint: ALWAYS check Tier 1 (built-in rules) and Tier 2 (configurable rules) BEFORE creating a custom plugin. See references/eslint-rules-discovery.md.
"Both could work → Regex first" NEVER applies to JavaScript/LWC/TypeScript files. JS/LWC/TS patterns MUST use ESLint — Regex cannot distinguish code from comments/strings in JS and produces false positives. Do NOT rationalize Regex for JS files based on "simplicity" or "no npm dependencies."
Tell the user which engine you chose and why. Respect their preference if they disagree.
Excluding Test Classes — Strategy by Engine
When a rule should NOT apply to test classes, the approach differs by engine:
| Engine | How to exclude test classes | Notes | |
|---|---|---|---|
| PMD (Apex) | Add [not(ancestor::UserClass[ModifierNode[@Test = true()]])] to the XPath | Structural exclusion — works perfectly, no config changes needed | |
| Regex | Use ignores.files in code-analyzer.yml with globs like **/*Test.cls | regex_ignore is per-LINE, not per-FILE — it CANNOT exclude entire test classes. Only use regex_ignore for per-line patterns like // NOPMD | |
| ESLint | Use ignores array in eslint.config.js | Standard ESLint file-level ignores |
`regex_ignore` is NOT file-level exclusion. It only skips matches on lines that ALSO match the ignore pattern. Example: regex_ignore: "/@isTest/i" only suppresses violations on lines containing @isTest — a SOQL query on line 50 of a test class still flags because line 50 doesn't contain @isTest. To exclude test files from regex rules entirely, use:
`ignores.files` is GLOBAL — it affects ALL engines and ALL rules. If you need test-class exclusion for some rules but not others (e.g., exclude tests from SOQL rules but still scan tests for @AuraEnabled), use PMD with XPath for the rules that need selective exclusion. PMD's XPath can structurally check @Test = true() per-method or per-class — Regex cannot.
Decision guide for Apex rules that should skip test classes:
- If the pattern is structural (method calls, annotations, nesting) → use PMD. XPath handles test-class exclusion natively.
- If the pattern is purely textual AND all regex rules should skip tests → use Regex +
ignores.files. - If you have a mix (some rules skip tests, others don't) → use PMD for the test-sensitive rules, Regex for the others.
Workflow
When User Selects Code (IDE Selection)
When the user highlights a code block in their editor and asks to "catch this", "flag this pattern", "create a rule for this", or similar:
- The selection IS your positive sample. Do NOT ask "what pattern should this rule flag?" — the user already showed you. Do NOT write a new sample from scratch.
- Identify what's structural vs. incidental in the selection:
- Structural (rule-worthy): the method call, the loop pattern, the missing keyword, the nesting
- Incidental (ignore): specific variable names, string values, parameter counts
- Ask ONE question if ambiguous: "Should the rule catch all
System.debugcalls, or only those without a LoggingLevel parameter?"
- Ast-dump the ACTUAL file the user has open (not a new sample file):
``bash sf code-analyzer ast-dump --file <the-open-file.cls> --output-file <ast.xml> ``
- Find the selection in the AST output — locate the nodes corresponding to the highlighted lines. These are your target nodes.
- Generalize the XPath — write XPath that matches the structural pattern, NOT the specific instance. Replace specific variable names with wildcards, keep structural nodes and discriminating attributes.
- Continue with standard workflow (negative sample, create rule, validate, test positive + negative).
Example flow:
- User selects:
Database.query('SELECT Id FROM ' + objectName) - Structural pattern:
Database.querycall (dynamic SOQL) - Incidental: the specific string concatenation inside
- Engine: PMD (structural call detection)
- XPath:
//MethodCallExpression[@FullMethodName='Database.query'] - NOT: regex matching
Database.query(would miss multiline, match comments)
Example flow (block selection):
- User selects a 5-line block with SOQL inside a for-each loop
- Structural: SOQL query as descendant of loop body
- Incidental: specific query fields, variable names
- Engine: PMD
- Ast-dump the open file → find ForEachStatement + SoqlExpression in body
- XPath:
//ForEachStatement/BlockStatement//SoqlExpression
For Regex Rules
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 95 of 100Pattern checks on the skill's files.
- Model reviewPassed
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingskills/dx-code-analyzer-custom-rule-create/SKILL.md
Popularity
- Repository stars
- 971
- Repository forks
- 329
- Repository npm downloads, 7 days
- 100,641
- 7-day trend score
- 60
Stars and forks are for the whole GitHub repository, not this skill alone. Downloads are for the repository's npm package. Refreshed 7 Sep 2026, 2 months ago.
Extension points
pluginCustom plugin integration
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/forcedotcom/sf-skills/dx-code-analyzer-custom-rule-create)