npx skills add ...
npx skills add forcedotcom/sf-skills --skill platform-environment-validate
Validate and configure the local Salesforce development environment. Runs a prerequisite scan showing π΄/π‘/π’ status for all required tools (Salesforce CLI, Code Analyzer plugin, Node.js, NPM, Git, Salesforce MCP, Source Tracking) and offers to install or update missing/outdated items. TRIGGER when the user runs /salesforce-development:platform-environment-validate, asks to 'check my setup', 'validate tools', 'verify prerequisites', 'am I set up correctly', or reports that a tool is missing or not working. DO NOT TRIGGER for: org authentication issues (use /salesforce-development:login), deployment problems (use platform-metadata-deploy), or general status checks (use /salesforce-development:status).
npx skills add forcedotcom/sf-skills --skill platform-environment-validate
Validate all required prerequisites and surface a clear, actionable status report. This skill is on-demand β it does not run automatically on session start. Run it explicitly to check or repair your local setup.
Run the tool check:
The output is a JSON object with a tools array (plus a diagnostic block on any critical failure).
The banner is painted for you β do not reproduce it. When check-tools runs, the plugin paints the framed "Ready to build on Salesforce?" banner deterministically on the visible channel β one status row per tool, the footer verdict, and the wayfinding footer β exactly like the SessionStart banner. It is a Tier-1 surface: read the JSON for your own understanding, but do NOT reproduce, redraw, or re-render the banner. Add only a short read of what the result means for the user, then go to Phase 2.
The painted banner looks like this (illustrative β the version/message text in each row comes straight from the JSON: version for π’, message + fix hint for π‘/π΄, the note for βΉοΈ; the values below show the style, not fixed strings):
Each row's status dot carries the state β π΄ critical (missing or below minimum β Salesforce development cannot proceed), π‘ warn (installed but outdated, non-LTS, or misconfigured), π’ ok, βΉοΈ info (a contextual note that can't be auto-verified, e.g. MCP process health) β and the framed footer gives the verdict plus the single most relevant Next: step. The JSON status field is the source of truth per tool; use these states when you write your short read.
If the banner did not paint (an older Claude Code build, or a paint fallback), do not hand-render it from the JSON. Print it with the deterministic renderer instead:
This reads the same scan result check-tools just recorded and prints the identical framed banner β rows in fixed order, the footer verdict, and the "you don't memorize commands here" wayfinding footer with its Next: step β so ordering, padding, counts, and next-step selection are decided once in the script, never re-derived by hand. The check-tools JSON stays the authoritative, machine-readable result.
Deterministic results β do NOT override a failure: the JSON report
is the authoritative, machine-readable result. If a tool reports π΄/π‘, report it
as-is. Do not re-run the tool a different way (PowerShell, a raw shell probe,
a different command) and then present the result as π’ β a fallback that happens
to find the tool does not mean the deterministic check passed. A failed check
must stay failed until that same check-tools check passes. When the report
includes a diagnostic block (attached on any critical failure), surface it: it
carries the platform, active shell, working directory, plugin root, and the
resolved executable paths β the fastest way to see why a tool didn't resolve
(e.g. a Windows sf.cmd not on PATH). The diagnostic is secret-free by design;
never add tokens or org auth to it.
MCP is reported as three distinct rows β never inferred from one another:
Salesforce MCP (config) (is .mcp.json + the sf-mcp-proxy.bundled.js present?),
Salesforce MCP (endpoint) (is the platform endpoint reachable?), and
Salesforce MCP (process) (is the MCP process actually healthy?). The process row
is reported as βΉοΈ informational (not a warning) β this script cannot see the
MCP subprocess that Claude Code owns, so a green config/endpoint must not be
presented as a working MCP. Confirm process health with /mcp or /doctor. The
endpoint row probes the org instance URL as a connectivity proxy, not the
platform-MCP endpoint itself.
| Tool | Minimum Requirement | Verification |
|---|---|---|
| Salesforce CLI | Present, and on the latest release | sf --version (π‘ when an update is available) |
| Code Analyzer plugin | Installed or JIT-registered | sf plugins inspect @salesforce/plugin-code-analyzer, falling back to the CLI's oclif.jitPlugins registry |
| Node.js | >= 18 (even/LTS) | node --version |
| NPM | >= 3.10 | npm --version |
| Git | Must be present | git --version |
| Salesforce MCP (config) | .mcp.json configured + proxy bundle present | Plugin root .mcp.json check + sf-mcp-proxy.bundled.js presence |
| Salesforce MCP (endpoint) | Org instance URL reachable (connectivity proxy) | HTTP probe of org instance URL |
| Salesforce MCP (process) | βΉοΈ informational β not verifiable here | Confirm with /mcp or /doctor |
| Source Tracking | Enabled for connected org | sf project deploy preview |
All external tools (sf, npm, node, git) are launched through a single
cross-platform resolver: shutil.which (PATHEXT-aware) finds the tool,
and a Windows .cmd/.bat shim (sf.cmd, npm.cmd) is invoked via a
COMSPEC-wrapped argv array β never a shell string β so this scan and
/salesforce-development:org detect sf/npm/the default org correctly on
Windows, macOS, and Linux.
Code Analyzer is a JIT plugin β registered β installed. The Salesforce CLI
declares @salesforce/plugin-code-analyzer as a "just-in-time" (JIT) plugin: it
is only physically installed the first time a sf code-analyzer command runs.
Until then, sf plugins inspect fails for it even though it is fully
available to the user. The check therefore treats JIT registration as success β
if inspect returns no version, it falls back to the CLI's own
oclif.jitPlugins registry (read from the root entry of sf plugins --json) and
reports π’ with the pinned version and a note that it auto-installs on first use.
Only a plugin that is neither installed nor JIT-registered is π΄ critical.
If all green: Confirm setup is complete. The user is ready to develop.
If warnings or critical items exist: Present the user with options:
For each tool the user wants to fix, provide the correct install/update command for their OS. Do not run install commands automatically β show the command and ask the user to confirm before running it.
Salesforce CLI β not installed:
Salesforce CLI β update:
Code Analyzer plugin β not installed:
Code Analyzer plugin β update:
Node.js β not installed or below minimum:
NPM β update:
Git β not installed:
Source Tracking β not enabled:
Salesforce MCP β misconfigured: If .mcp.json is missing or empty, reload the plugin:
/salesforce-development:login first./salesforce-development:login instead of this skill.check-tools reports the Salesforce CLI as π‘ (installed but outdated) with the correct update command, rather than π’. Unlike the session-start notice below, this warning ignores the per-version no-nag gate β an explicit readiness scan always reports the factual state β but it still honors the hard opt-out SFDX_SKIP_CLI_UPDATE_CHECK=1.sf-context detect SessionStart hook surfaces it once and asks the agent to offer the update (sf update, or npm install --global @salesforce/cli@latest for npm-global installs). Declining or a failed update records a per-version no-nag gate (.sf/sf-cli-update-state.json) so the same version won't nag again, but a newer release will re-prompt. Set SFDX_SKIP_CLI_UPDATE_CHECK=1 to disable the check entirely.