sf-apex: Salesforce Apex Code Generation and Review
Expert Apex developer specializing in clean code, SOLID principles, and 2025 best practices. Generate production-ready, secure, performant, and maintainable Apex code.
Core Responsibilities Code Generation: Create Apex classes, triggers (TAF), tests, async jobs from requirements Code Review: Analyze existing Apex for best practices violations with actionable fixes Validation & Scoring: Score code against 8 categories (0-150 points) Deployment Integration: Validate and deploy via sf-deploy skill Workflow (5-Phase Pattern) Phase 1: Requirements Gathering
Use AskUserQuestion to gather:
Class type (Trigger, Service, Selector, Batch, Queueable, Test, Controller) Primary purpose (one sentence) Target object(s) Test requirements
Then:
Check existing code: Glob: /*.cls, Glob: /.trigger Check for existing Trigger Actions Framework setup: Glob: /TriggerAction*.cls Create TodoWrite tasks Phase 2: Design & Template Selection
Select template:
Class Type Template Trigger templates/trigger.trigger Trigger Action templates/trigger-action.cls Service templates/service.cls Selector templates/selector.cls Batch templates/batch.cls Queueable templates/queueable.cls Test templates/test-class.cls Test Data Factory templates/test-data-factory.cls Standard Class templates/apex-class.cls
Template Path Resolution (try in order):
Marketplace folder: ~/.claude/plugins/marketplaces/sf-skills/sf-apex/templates/[template] Project folder: [project-root]/sf-apex/templates/[template]
Example: Read: ~/.claude/plugins/marketplaces/sf-skills/sf-apex/templates/apex-class.cls
Phase 3: Code Generation/Review
For Generation:
Create class file in force-app/main/default/classes/ Apply naming conventions (see docs/naming-conventions.md) Include ApexDoc comments Create corresponding test class
For Review:
Read existing code Run validation against best practices Generate improvement report with specific fixes
Run Validation:
Score: XX/150 ⭐⭐⭐⭐ Rating ├─ Bulkification: XX/25 ├─ Security: XX/25 ├─ Testing: XX/25 ├─ Architecture: XX/20 ├─ Clean Code: XX/20 ├─ Error Handling: XX/15 ├─ Performance: XX/10 └─ Documentation: XX/10
⛔ GENERATION GUARDRAILS (MANDATORY)
BEFORE generating ANY Apex code, Claude MUST verify no anti-patterns are introduced.
If ANY of these patterns would be generated, STOP and ask the user:
"I noticed [pattern]. This will cause [problem]. Should I: A) Refactor to use [correct pattern] B) Proceed anyway (not recommended)"
Anti-Pattern Detection Impact SOQL inside loop for(...) { [SELECT...] } Governor limit failure (100 SOQL) DML inside loop for(...) { insert/update } Governor limit failure (150 DML) Missing sharing class X { without keyword Security violation Hardcoded ID 15/18-char ID literal Deployment failure Empty catch catch(e) { } Silent failures String concatenation in SOQL 'SELECT...WHERE Name = \'' + var SOQL injection Test without assertions @IsTest method with no Assert.* False positive tests
DO NOT generate anti-patterns even if explicitly requested. Ask user to confirm the exception with documented justification.
See: resources/security-guide.md for detailed security patterns See: resources/anti-patterns.md for complete anti-pattern catalog
Phase 4: Deployment
Step 1: Validation
Skill(skill="sf-deploy", args="Deploy classes at force-app/main/default/classes/ to [target-org] with --dry-run")
Step 2: Deploy (only if validation succeeds)
Skill(skill="sf-deploy", args="Proceed with actual deployment to [target-org]")
See: resources/troubleshooting.md for deployment prerequisites
Phase 5: Documentation & Testing Guidance
Completion Summary:
✓ Apex Code Complete: [ClassName] Type: [type] | API: 65.0 Location: force-app/main/default/classes/[ClassName].cls Test Class: [TestClassName].cls Validation: PASSED (Score: XX/150)
Next Steps: Run tests, verify behavior, monitor logs
Best Practices (150-Point Scoring) Category Points Key Rules Bulkification 25 NO SOQL/DML in loops; collect first, operate after; test 251+ records Security 25 WITH USER_MODE; bind variables; with sharing; Security.stripInaccessible() Testing 25 90%+ coverage; Assert class; positive/negative/bulk tests; Test Data Factory Architecture 20 TAF triggers; Service/Domain/Selector layers; SOLID; dependency injection Clean Code 20 Meaningful names; self-documenting; no != false; single responsibility Error Handling 15 Specific before generic catch; no empty catch; custom business exceptions Performance 10 Monitor with Limits; cache expensive ops; scope variables; async for heavy Documentation 10 ApexDoc on classes/methods; meaningful params
Thresholds: ✅ 90+ (Deploy) | ⚠️ 67-89 (Review) | ❌ <67 (Block - fix required)
Deep Dives:
resources/bulkification-guide.md - Governor limits, collection handling resources/security-guide.md - CRUD/FLS, sharing, injection prevention resources/testing-patterns.md - Exception types, mocking, coverage resources/patterns-deep-dive.md - TAF, @InvocableMethod, async patterns Trigger Actions Framework (TAF) Quick Reference
When to Use: If TAF package is installed in target org (check: sf package installed list)
Trigger Pattern (one per object):
trigger AccountTrigger on Account (before insert, after insert, before update, after update, before delete, after delete, after undelete) { new MetadataTriggerHandler().run(); }
Action Class (one per behavior):
public class TA_Account_SetDefaults implements TriggerAction.BeforeInsert {
public void beforeInsert(List
⚠️ CRITICAL: TAF triggers do NOTHING without Trigger_Action__mdt records! Each action class needs a corresponding Custom Metadata record.
Installation:
sf package install --package 04tKZ000000gUEFYA2 --target-org [alias] --wait 10
Fallback: If TAF is NOT installed, use standard trigger pattern (see resources/patterns-deep-dive.md)
See: resources/patterns-deep-dive.md for complete TAF patterns and Custom Metadata setup
Async Decision Matrix Scenario Use Simple callout, fire-and-forget @future(callout=true) Complex logic, needs chaining Queueable Process millions of records Batch Apex Scheduled/recurring job Schedulable Post-queueable cleanup Queueable Finalizer
See: resources/patterns-deep-dive.md for detailed async patterns
Modern Apex Features (API 62.0) Null coalescing: value ?? defaultValue Safe navigation: record?.Field__c User mode: WITH USER_MODE in SOQL Assert class: Assert.areEqual(), Assert.isTrue()
Breaking Change (API 62.0): Cannot modify Set while iterating - throws System.FinalException
See: resources/bulkification-guide.md for collection usage
Flow Integration (@InvocableMethod)
Apex classes can be called from Flow using @InvocableMethod. This pattern enables complex business logic, DML, callouts, and integrations from declarative automation.
Quick Pattern public with sharing class RecordProcessor {
@InvocableMethod(label='Process Record' category='Custom')
public static List<Response> execute(List<Request> requests) {
List<Response> responses = new List<Response>();
for (Request req : requests) {
Response res = new Response();
res.isSuccess = true;
res.processedId = req.recordId;
responses.add(res);
}
return responses;
}
public class Request {
@InvocableVariable(label='Record ID' required=true)
public Id recordId;
}
public class Response {
@InvocableVariable(label='Is Success')
public Boolean isSuccess;
@InvocableVariable(label='Processed ID')
public Id processedId;
}
}
Template: Use templates/invocable-method.cls for complete pattern
See:
resources/patterns-deep-dive.md - Complete @InvocableMethod guide docs/flow-integration.md - Advanced Flow-Apex patterns docs/triangle-pattern.md - Flow-LWC-Apex triangle Testing Best Practices The 3 Test Types (PNB Pattern)
Every feature needs:
Positive: Happy path test Negative: Error handling test Bulk: 251+ records test
Example:
@IsTest static void testPositive() { Account acc = new Account(Name = 'Test', Industry = 'Tech'); insert acc; Assert.areEqual('Tech', [SELECT Industry FROM Account WHERE Id = :acc.Id].Industry); }
@IsTest static void testNegative() { try { insert new Account(); // Missing Name Assert.fail('Expected DmlException'); } catch (DmlException e) { Assert.isTrue(e.getMessage().contains('REQUIRED_FIELD_MISSING')); } }
@IsTest
static void testBulk() {
List
See:
resources/testing-patterns.md - Exception types, mocking, Test Data Factory docs/testing-guide.md - Complete testing reference Common Exception Types
When writing test classes, use these specific exception types:
Exception Type When to Use DmlException Insert/update/delete failures QueryException SOQL query failures NullPointerException Null reference access ListException List operation failures LimitException Governor limit exceeded CalloutException HTTP callout failures
Example:
@IsTest static void testExceptionHandling() { try { insert new Account(); // Missing required Name Assert.fail('Expected DmlException was not thrown'); } catch (DmlException e) { Assert.isTrue(e.getMessage().contains('REQUIRED_FIELD_MISSING'), 'Expected REQUIRED_FIELD_MISSING but got: ' + e.getMessage()); } }
See: resources/testing-patterns.md for complete reference
LSP-Based Validation (Auto-Fix Loop)
The sf-apex skill includes Language Server Protocol (LSP) integration for real-time syntax validation. This enables Claude to automatically detect and fix Apex syntax errors during code authoring.
How It Works PostToolUse Hook: After every Write/Edit operation on .cls or .trigger files, the LSP hook validates syntax Apex Language Server: Uses Salesforce's official apex-jorje-lsp.jar (from VS Code extension) Auto-Fix Loop: If errors are found, Claude receives diagnostics and auto-fixes them (max 3 attempts) Two-Layer Validation: LSP Validation: Fast syntax checking (~500ms) 150-Point Validation: Semantic analysis for best practices Prerequisites
For LSP validation to work, users must have:
VS Code Salesforce Extension Pack: VS Code → Extensions → "Salesforce Extension Pack" Java 11+: https://adoptium.net/temurin/releases/
Graceful Degradation: If LSP is unavailable, validation silently skips - the skill continues to work with only 150-point semantic validation.
See: resources/troubleshooting.md for complete LSP guide
Cross-Skill Integration Skill When to Use Example sf-metadata Discover object/fields before coding Skill(skill="sf-metadata") → "Describe Invoice__c" sf-data Generate 251+ test records after deploy Skill(skill="sf-data") → "Create 251 Accounts for bulk testing" sf-deploy Deploy to org - see Phase 4 Skill(skill="sf-deploy", args="Deploy to [org]") sf-flow Create Flow that calls your Apex See @InvocableMethod section above sf-lwc Create LWC that calls your Apex @AuraEnabled controller patterns Reference Documentation Quick Guides (resources/) Guide Description patterns-deep-dive.md TAF, @InvocableMethod, async patterns, service layer security-guide.md CRUD/FLS, sharing, SOQL injection, guardrails bulkification-guide.md Governor limits, collections, monitoring testing-patterns.md Exception types, mocking, Test Data Factory, coverage anti-patterns.md Code smells, red flags, refactoring patterns troubleshooting.md LSP validation, deployment errors, debug logs Full Documentation (docs/) Document Description best-practices.md Bulkification, collections, null safety, guard clauses, DML performance code-smells-guide.md Code smells detection and refactoring patterns design-patterns.md 12 patterns including Domain Class, Abstraction Levels trigger-actions-framework.md TAF setup and advanced patterns security-guide.md Complete CRUD/FLS and sharing reference testing-guide.md Complete test patterns and mocking naming-conventions.md Variable, method, class naming rules solid-principles.md SOLID principles for Apex code-review-checklist.md 150-point scoring criteria flow-integration.md Complete @InvocableMethod guide triangle-pattern.md Flow-LWC-Apex integration llm-anti-patterns.md NEW: Common LLM code generation mistakes (Java types, non-existent methods, Map patterns)
Path: ~/.claude/plugins/marketplaces/sf-skills/sf-apex/docs/
Dependencies
All optional: sf-deploy, sf-metadata, sf-data. Install: /plugin install github:Jaganpro/sf-skills/[skill-name]
Notes API Version: 62.0 required TAF Optional: Prefer TAF when package is installed, use standard trigger pattern as fallback Scoring: Block deployment if score < 67 LSP: Optional but recommended for real-time syntax validation License
MIT License. See LICENSE file. Copyright (c) 2024-2025 Jag Valaiyapathy