sf-apex

Original🇺🇸 English
Translated
5 scriptsChecked / no sensitive code detected

Generates and reviews Salesforce Apex code with 2025 best practices and 150-point scoring. Use when writing Apex classes, triggers, test classes, batch jobs, or reviewing existing Apex code for bulkification, security, and SOLID principles.

5installs
Added on

NPX Install

npx skill4agent add jaganpro/sf-skills sf-apex

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

  1. Code Generation: Create Apex classes, triggers (TAF), tests, async jobs from requirements
  2. Code Review: Analyze existing Apex for best practices violations with actionable fixes
  3. Validation & Scoring: Score code against 8 categories (0-150 points)
  4. 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:
  1. Check existing code:
    Glob: **/*.cls
    ,
    Glob: **/*.trigger
  2. Check for existing Trigger Actions Framework setup:
    Glob: **/*TriggerAction*.cls
  3. Create TodoWrite tasks

Phase 2: Design & Template Selection

Select template:
Class TypeTemplate
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):
  1. Marketplace folder:
    ~/.claude/plugins/marketplaces/sf-skills/sf-apex/templates/[template]
  2. 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:
  1. Create class file in
    force-app/main/default/classes/
  2. Apply naming conventions (see docs/naming-conventions.md)
  3. Include ApexDoc comments
  4. Create corresponding test class
For Review:
  1. Read existing code
  2. Run validation against best practices
  3. 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-PatternDetectionImpact
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 ID15/18-char ID literalDeployment 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)

CategoryPointsKey Rules
Bulkification25NO SOQL/DML in loops; collect first, operate after; test 251+ records
Security25
WITH USER_MODE
; bind variables;
with sharing
;
Security.stripInaccessible()
Testing2590%+ coverage; Assert class; positive/negative/bulk tests; Test Data Factory
Architecture20TAF triggers; Service/Domain/Selector layers; SOLID; dependency injection
Clean Code20Meaningful names; self-documenting; no
!= false
; single responsibility
Error Handling15Specific before generic catch; no empty catch; custom business exceptions
Performance10Monitor with
Limits
; cache expensive ops; scope variables; async for heavy
Documentation10ApexDoc 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):
apex
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):
apex
public class TA_Account_SetDefaults implements TriggerAction.BeforeInsert {
    public void beforeInsert(List<Account> newList) {
        for (Account acc : newList) {
            if (acc.Industry == null) {
                acc.Industry = 'Other';
            }
        }
    }
}
⚠️ CRITICAL: TAF triggers do NOTHING without
Trigger_Action__mdt
records! Each action class needs a corresponding Custom Metadata record.
Installation:
bash
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

ScenarioUse
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

apex
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:
  1. Positive: Happy path test
  2. Negative: Error handling test
  3. Bulk: 251+ records test
Example:
apex
@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<Account> accounts = new List<Account>();
    for (Integer i = 0; i < 251; i++) {
        accounts.add(new Account(Name = 'Bulk ' + i));
    }
    insert accounts;
    Assert.areEqual(251, [SELECT COUNT() FROM Account]);
}
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 TypeWhen 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:
apex
@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

  1. PostToolUse Hook: After every Write/Edit operation on
    .cls
    or
    .trigger
    files, the LSP hook validates syntax
  2. Apex Language Server: Uses Salesforce's official
    apex-jorje-lsp.jar
    (from VS Code extension)
  3. Auto-Fix Loop: If errors are found, Claude receives diagnostics and auto-fixes them (max 3 attempts)
  4. 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:
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

SkillWhen to UseExample
sf-metadataDiscover object/fields before coding
Skill(skill="sf-metadata")
→ "Describe Invoice__c"
sf-dataGenerate 251+ test records after deploy
Skill(skill="sf-data")
→ "Create 251 Accounts for bulk testing"
sf-deployDeploy to org - see Phase 4
Skill(skill="sf-deploy", args="Deploy to [org]")
sf-flowCreate Flow that calls your ApexSee @InvocableMethod section above
sf-lwcCreate LWC that calls your Apex
@AuraEnabled
controller patterns

Reference Documentation

Quick Guides (resources/)

GuideDescription
patterns-deep-dive.mdTAF, @InvocableMethod, async patterns, service layer
security-guide.mdCRUD/FLS, sharing, SOQL injection, guardrails
bulkification-guide.mdGovernor limits, collections, monitoring
testing-patterns.mdException types, mocking, Test Data Factory, coverage
anti-patterns.mdCode smells, red flags, refactoring patterns
troubleshooting.mdLSP validation, deployment errors, debug logs

Full Documentation (docs/)

DocumentDescription
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