
Salesforce Apex Quality
Review or generate Salesforce Apex, triggers, batch jobs, and tests with governor-limit, security, and PNB coverage guardrails before deploy.
Overview
salesforce-apex-quality is an agent skill most often used in Ship (also Build backend, Ship security) that enforces bulk-safe Apex, sharing and CRUD/FLS rules, and PNB test coverage before deployment.
Install
npx skills add https://github.com/github/awesome-copilot --skill salesforce-apex-qualityWhat is this skill?
- Step 1 governor safety: automatic fail on SOQL/DML inside loops with bulk-safe patterns
- Sharing model, CRUD/FLS, and SOQL injection prevention checks
- PNB test coverage pattern: Positive, Negative, and Bulk test scenarios
- Applies to Apex classes, trigger handlers, batch jobs, and test classes
- Modern Apex idioms enforced on every file you write or review
- Step 1 governor limit safety check is the first mandatory review step
Adoption & trust: 671 installs on skills.sh; 34.6k GitHub stars; 3/3 security scanners passed (skills.sh audits).
What problem does it solve?
Your agent-generated Apex looks fine in a sandbox but will throw LimitException or expose data because loops hide SOQL/DML and weak tests.
Who is it for?
Indie Salesforce developers using AI to write triggers and services who need a fixed pre-deploy quality gate.
Skip if: Non-Salesforce stacks, or teams that only need LWC/CSS review without Apex governor and security rules.
When should I use this skill?
Use when reviewing or generating Apex classes, trigger handlers, batch jobs, or test classes to catch governor limit risks, security gaps, and quality issues before deployment.
What do I get? / Deliverables
After applying the guardrails, Apex and tests follow bulk-safe queries, proper sharing and FLS checks, injection-safe SOQL, and Positive-Negative-Bulk test structure ready for deploy review.
- Bulk-safe Apex revisions with loop-free SOQL/DML
- Test classes structured for Positive, Negative, and Bulk scenarios
Recommended Skills
Journey fit
Spans multiple journey phases - primary shelf plus alternate fits below.
Canonical shelf is Ship → review because the skill’s stated use is catching governor risks, security gaps, and quality issues before deployment. Subphase review matches Apex quality guardrails applied while reviewing classes, trigger handlers, and test files—not greenfield UI design.
Where it fits
Generate a trigger handler that collects IDs first then runs one SOQL and one DML batch per the skill’s loop anti-patterns.
Run the governor Step 1 scan on a copilot-written service class before opening a promotion PR.
Verify CRUD/FLS and injection-safe dynamic SOQL on integration endpoints before customer UAT.
How it compares
A Salesforce-specific Apex checker—not a generic Java linter or OWASP web-app scan.
Common Questions / FAQ
Who is salesforce-apex-quality for?
Solo and small-team Salesforce builders who want every Apex class, trigger handler, batch job, and test vetted for governor limits and security before shipping.
When should I use salesforce-apex-quality?
In Build backend while drafting handlers; in Ship review before promoting to production; and in Ship security passes when validating CRUD/FLS and SOQL injection fixes on existing code.
Is salesforce-apex-quality safe to install?
It is a review guideline skill with no inherent network calls—still review the Security Audits panel on this Prism page and never skip human review on production org changes.
SKILL.md
READMESKILL.md - Salesforce Apex Quality
# Salesforce Apex Quality Guardrails Apply these checks to every Apex class, trigger, and test file you write or review. ## Step 1 — Governor Limit Safety Check Scan for these patterns before declaring any Apex file acceptable: ### SOQL and DML in Loops — Automatic Fail ```apex // ❌ NEVER — causes LimitException at scale for (Account a : accounts) { List<Contact> contacts = [SELECT Id FROM Contact WHERE AccountId = :a.Id]; // SOQL in loop update a; // DML in loop } // ✅ ALWAYS — collect, then query/update once Set<Id> accountIds = new Map<Id, Account>(accounts).keySet(); Map<Id, List<Contact>> contactsByAccount = new Map<Id, List<Contact>>(); for (Contact c : [SELECT Id, AccountId FROM Contact WHERE AccountId IN :accountIds]) { if (!contactsByAccount.containsKey(c.AccountId)) { contactsByAccount.put(c.AccountId, new List<Contact>()); } contactsByAccount.get(c.AccountId).add(c); } update accounts; // DML once, outside the loop ``` Rule: if you see `[SELECT` or `Database.query`, `insert`, `update`, `delete`, `upsert`, `merge` inside a `for` loop body — stop and refactor before proceeding. ## Step 2 — Sharing Model Verification Every class must declare its sharing intent explicitly. Undeclared sharing inherits from the caller — unpredictable behaviour. | Declaration | When to use | |---|---| | `public with sharing class Foo` | Default for all service, handler, selector, and controller classes | | `public without sharing class Foo` | Only when the class must run elevated (e.g. system-level logging, trigger bypass). Requires a code comment explaining why. | | `public inherited sharing class Foo` | Framework entry points that should respect the caller's sharing context | If a class does not have one of these three declarations, **add it before writing anything else**. ## Step 3 — CRUD / FLS Enforcement Apex code that reads or writes records on behalf of a user must verify object and field access. The platform does **not** enforce FLS or CRUD automatically in Apex. ```apex // Check before querying a field if (!Schema.sObjectType.Contact.fields.Email.isAccessible()) { throw new System.NoAccessException(); } // Or use WITH USER_MODE in SOQL (API 56.0+) List<Contact> contacts = [SELECT Id, Email FROM Contact WHERE AccountId = :accId WITH USER_MODE]; // Or use Database.query with AccessLevel List<Contact> contacts = Database.query('SELECT Id, Email FROM Contact', AccessLevel.USER_MODE); ``` Rule: any Apex method callable from a UI component, REST endpoint, or `@InvocableMethod` **must** enforce CRUD/FLS. Internal service methods called only from trusted contexts may use `with sharing` instead. ## Step 4 — SOQL Injection Prevention ```apex // ❌ NEVER — concatenates user input into SOQL string String soql = 'SELECT Id FROM Account WHERE Name = \'' + userInput + '\''; // ✅ ALWAYS — bind variable String soql = [SELECT Id FROM Account WHERE Name = :userInput]; // ✅ For dynamic SOQL with user-controlled field names — validate against a whitelist Set<String> allowedFields = new Set<String>{'Name', 'Industry', 'AnnualRevenue'}; if (!allowedFields.contains(userInput)) { throw new IllegalArgumentException('Field not permitted: ' + userInput); } ``` ## Step 5 — Modern Apex Idioms Prefer current language features (API 62.0 / Winter '25+): | Old pattern | Modern replacement | |---|---| | `if (obj != null) { x = obj.Field__c; }` | `x = obj?.Field__c;` | | `x = (y != null) ? y : defaultVal;` | `x = y ?? def