Skip to content
Development
Skill

/dx-apexguru-scan

Run an ApexGuru performance scan on a Salesforce Apex project via the ApexGuru SFAP Scan API. Zips the project's Apex (any layout), submits it, polls to completion, decodes the base64 report, and presents performance antipattern violations (SOQL in loop, DML in loop,

From plugin
sf-skills
1.1k200 skills6 agents15 commands4 MCP

Claude Code

$ npx -y skills add forcedotcom/sf-skills --skill dx-apexguru-scan --agent claude-code

SKILL.md

dx-apexguru-scan.SKILL.md
name: dx-apexguru-scan
description: "Run an ApexGuru performance scan on a Salesforce Apex project via the ApexGuru SFAP Scan API. Zips the project's Apex (any layout), submits it, polls to completion, decodes the base64 report, and presents performance antipattern violations (SOQL in loop, DML in loop, Schema.getGlobalDescribe(), SOQL without WHERE/LIMIT, unused SOQL fields) grouped by rule with severity, file:line, and suggested fixes — clearly attributed as 'Static only' or 'Production insights'. TRIGGER when the user says 'run ApexGuru', 'ApexGuru scan', 'check Apex performance', 'find governor-limit / performance antipatterns', 'SOQL in loop', 'scan my Apex for performance', or 'ApexGuru performance insights'. DO NOT TRIGGER for general static analysis or security scans (use dx-code-analyzer-run), for fixing code without scanning, or for onboarding an org to ApexGuru."
allowed-tools: Read, Bash(bash), Bash(node), Bash(curl), Bash(zip), Bash(unzip), Bash(jq), Bash(sf), Bash(date), Write
argument-hint: "[project-path] [--org <alias>] [--fast]"
metadata:
  version: "1.1"
  domains: ["Developer Experience"]
  relatedSkills:
    - "dx-code-analyzer-run"
  cliTools:
    - tool: ["curl"]
      semver: ">=7.0.0"
    - tool: ["jq"]
      semver: ">=1.6.0"
    - tool: ["node"]
      semver: ">=18.0.0"
    - tool: ["sf"]
      semver: ">=2.0.0"

ApexGuru Performance Scan Skill

CRITICAL: Mandatory Script Usage

Every step — token resolution, zipping, API calls, and report decoding — MUST go through the bundled scripts in `<skill_dir>/scripts/`. No exceptions.

WRONG — never do this:

# WRONG: hand-rolled curl to the API
curl -X POST https://api.salesforce.com/... -F file=@x.zip

# WRONG: inline base64 + jq to read the report
cat raw.json | jq -r .report | base64 -d | jq '.[]'

# WRONG: reading the raw result file directly (report is a large base64 blob)
Read tool → apexguru-raw-*.json

# WRONG: inline node/python to parse violations
node -e "const r = require('./raw.json'); ..."

RIGHT — always do this:

# PREFERRED — one command runs all three steps (package → submit+poll →
# decode+present) and prints the ready-to-show report as its final stdout.
# Use this for every initial scan: it cannot be left half-finished.
bash "<skill_dir>/scripts/scan.sh" "<project-root>"

# Optionally persist the presented markdown to a file as well:
bash "<skill_dir>/scripts/scan.sh" "<project-root>" --out ./apexguru-report.md

The three underlying scripts still exist and `scan.sh` calls them in order. Invoke them individually only for **drill-downs on an already-scanned result** (Step 5), or when you deliberately need to inspect an intermediate artifact:

# Equivalent manual chain (scan.sh runs exactly these, in this order):
bash "<skill_dir>/scripts/build-zip.sh" "<project-root>" "./apexguru-<TS>.zip"
bash "<skill_dir>/scripts/run-scan.sh"  "./apexguru-<TS>.zip" "./apexguru-raw-<TS>.json"
node "<skill_dir>/scripts/decode-report.js" "./apexguru-raw-<TS>.json" --present

# Drill into a subset WITHOUT re-scanning (reuse the raw file scan.sh left, or
# pass --raw to scan.sh to keep it at a known path):
node "<skill_dir>/scripts/decode-report.js" "./apexguru-raw-<TS>.json" --rule SOQL_IN_LOOP --full
node "<skill_dir>/scripts/decode-report.js" "./apexguru-raw-<TS>.json" --group file --top 5

`<skill_dir>` is the absolute path to the directory containing this SKILL.md. **Never** use `./scripts/` — that resolves against the user's CWD, not the skill dir.

Any filter/rank/group question ("which file has the most issues?", "show only SOQL-in-loop", "break down by severity") is answered by re-running `decode-report.js` with flags against the **same raw result file** — never re-scan, never parse the JSON by hand.

---

CRITICAL: Present `--present` output verbatim — never condense it

`decode-report.js --present` (Step 4) already produces the final, ready-to-show markdown: severity legend, one detail card per violation (message, code, fix, resource link), and a closing summary table. That stdout **is** the response. Print it to the user exactly as printed — do not rewrite it into a shorter table, do not drop the per-issue cards down to just the summary table, and do not wait for the user to ask "explain a violation" before including message/fix/resource. Condensing it defeats the entire point of `--present`.

The attribution is **already in that stdout** — the summary line is the exact output that states the mode (e.g. "ApexGuru (static analysis) is active. To unlock runtime intelligence…"). Do **NOT** prepend or append your own attribution sentence (no "Attribution: analysisMode: static…", no naming the org, no restating "static-only findings"). The script's line is the complete, approved wording; adding your own makes the output non-deterministic and off-message.

WRONG — never do this:

Top Issues (worst first)
#  Severity   Rule                      Method    Line
1  Major      UsingTheTestMethodKeyword legacy... 136
...
Key Antipatterns Detected:
- SOQL/DML in loops (3 violations)

*(a hand-built summary that drops every message/code/fix — even for violations that had one)*

Attribution: analysisMode: static — source-only analysis. The scanned org
(ag-skills-org) is not onboarded to ApexGuru's full runtime metrics, so
these are static-only findings.

*(an agent-authored attribution line prepended to the report — the script's own summary line already states the mode; this duplicate is non-deterministic and names an org the script never had access to)*

RIGHT — always do this:

Paste the full stdout from `decode-report.js --present` — every `### Issue N` card and the closing `## Summary` table — unedited, in one response.

---

Overview

ApexGuru detects **performance antipatterns** in Apex (SOQL/DML in loops, `Schema.getGlobalDescribe()`, SOQL without `WHERE`/`LIMIT`, unused SOQL fields). This skill drives the ApexGuru **SFAP Sc

Read more
@forcedotcom
Ships withsf-skills

This repository provides Salesforce agent skills, plugins, and sample apps for building applications.

1.1k200 skills6 agents4 MCP
Get the whole plugin

Stars on GitHub

Momentum

stars in total
1.1k
Star history of forcedotcom/sf-skills on GitHub, a chart by star-history.com

Other skills on sf-skills.

agentforce-observe

agentforce-observe

Analyze production Agentforce agent behavior using session traces and Data Cloud, and manage Agent Health Monitoring (AHM)…

More skills from other plugins.

brainstorming
Auto-invoked

brainstorming

You MUST use this before any creative work - creating features, building components, adding functionality, modifying behavior, or…

@obra@obraInstall Skill
ask-matt

ask-matt

Ask which skill or flow fits your situation. A router over the skills in this repo.

skills2w309k
@mattpocock@mattpocockInstall Skill
accessibility
Auto-invoked

accessibility

Design, implement, and audit accessible UI to WCAG 2.2 Level AA across Web, iOS, and Android — semantic ARIA roles and labels,…

ecc2w293k
@affaan-m@affaan-mInstall Skill
compiler-commit

compiler-commit

Use when you want to verify compiler changes and commit with the correct convention. Runs tests, lint, and format, then commits…

react5d252k
@facebook@facebookInstall Skill

Questions about dx-apexguru-scan.

Which coding agents can use dx-apexguru-scan?
dx-apexguru-scan installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.