Skip to Content
CLICommand ReferenceOrg Health & Operations

Org Health & Operations

Most commands here accept --org <alias> (defaults to config.defaultOrg) and --json.


sfdt audit

Diagnoses org health. Run a single check or all.

sfdt audit all sfdt audit mfa sfdt audit licenses --org production --json sfdt audit all --notify # also push the snapshot to notification channels
CheckWhat it inspects
audittrailRecent Setup Audit Trail entries (lookback audit.auditTrailLookbackDays)
licensesLicense usage vs audit.licenseWarnThreshold
mfaActive standard users with no registered MFA method
mfa-readinessUsers without phishing-resistant MFA (security key, WebAuthn, or built-in authenticator) ahead of the July 2026 enforcement
soap-loginsSOAP login() traffic on API versions 31–64 (retiring Summer ‘27; lookback audit.soapLoginLookbackDays)
unused-apexApex classes with zero test coverage (heuristic)
apex-unreferencedApex classes with no inbound metadata dependency
inactive-usersActive users with no recent login (beyond audit.inactiveUserDays)
api-versionsApex classes/triggers, Flows, LWC, and Aura below audit.minApiVersion (Flow/LWC/Aura degrade independently if an org can’t query them)
inactive-flowsFlow definitions with no active version
inactive-validationsValidation rules that are not active
inactive-workflowsWorkflow rules that are not active (legacy automation)
unused-permsetsPermission sets with no user or group assignment
connected-appsConnected apps that permit all users (admin approval off); also notes the External Client Apps migration
field-descriptionsCustom fields missing a description
lint-accessCustom objects with no Read access granted
lint-access-fieldsCustom fields with no Read access granted (field-level)

Results are written to logs/audit-latest.json (consumed by the dashboard and the VS Code Org Health sidebar). audit all exits non-zero when any check is fail or error, so it doubles as a CI gate.

OptionDescription
--notifyPush the snapshot to configured notification channels
--org <alias>Target org
--jsonStructured output

sfdt monitor

Monitors org operational health. Run a single check or all.

sfdt monitor all sfdt monitor limits sfdt monitor all --backup # include a metadata backup in the run sfdt monitor all --notify # push the snapshot to notification channels
CheckWhat it inspects
limitsGovernor-limit usage vs monitoring.limitWarnThreshold; reports the Summer ‘26 elastic async Apex entries when present and warns in the overflow band
errorsRecent failed async Apex jobs (last monitoring.errorLookbackDays days)
healthSecurity Health Check score vs monitoring.healthMinScore
org-infoInstance, edition, trial/expiration window (monitoring.orgInfoTrialWarnDays), and the org’s Salesforce release version and preview status
deploy-historyRecent deployment success/failure (latest failed → fail)
deprecated-apiTraffic on deprecated API versions (ApiTotalUsage logs)
flow-errorsPaused (potentially stuck) flow interviews
backupMetadata backup (see below)
OptionDescription
--backupInclude a metadata backup when running all
--notifyPush the snapshot to configured notification channels
--org <alias>Target org
--jsonStructured output

Results land in logs/monitor-latest.json. monitor all exits non-zero when any check is fail or error.

Graceful degradation

Some checks depend on Beta or license-gated objects (MetadataComponentDependency, DeployRequest, FlowInterview, ConnectedApplication, ValidationRule/WorkflowRule, EventLogFile). When an org can’t run one of these, the check returns warn (“unavailable …”) rather than error, so audit all / monitor all never fail CI just because an org lacks a particular API or license.

sfdt monitor backup

Retrieves a full metadata backup into monitoring.backupDir.

sfdt monitor backup sfdt monitor backup --org production --json

sfdt docs

Generates documentation and diagrams from your org/source.

sfdt docs generate # objects, Apex, flows (MkDocs-compatible) sfdt docs generate --ai # force the AI overview on sfdt docs generate --no-ai # force the AI overview off sfdt docs generate --roles developer,admin # per-component role guides (AI) sfdt docs generate --no-diagrams # skip the standalone ER-diagram page sfdt docs diagram # print a Mermaid ER diagram sfdt docs diagram --output erd.mmd
SubcommandOptions
docs generate--ai / --no-ai, --roles [list], --no-diagrams, --json
docs diagram--output <file>, --json

Config-driven docs. With no flags, docs generate follows config: the AI overview is on when features.ai && docs.ai !== false (--no-ai/--ai override either way); per-component Developer/Admin/User/DevOps guides are emitted when docs.roleGuides is enabled (scoped by docs.roles, or --roles [list]); and the standalone ER-diagram page (diagrams/erd.md, linked in the MkDocs nav) is emitted when docs.diagrams is enabled (--no-diagrams to opt out). Role guides and AI overviews both require features.ai.


sfdt data

Manages data sets via the native sf data tree, for seeding sandboxes and scratch orgs.

sfdt data list sfdt data export AccountsAndContacts sfdt data import AccountsAndContacts sfdt data delete AccountsAndContacts --yes
SubcommandDescription
listList defined data sets
export [set]Export records to a data set
import [set]Import a data set into the org
load [set]Load a data set over Bulk API v2 (insert or upsert)
delete [set]Delete records the set’s queries match

Common options: --org <alias>, --json.

load and delete both write, so both carry a production guard (--production) and a confirmation that refuses rather than auto-confirms when non-interactive (--yes to skip it). load inserts or upserts, and an upsert overwrites records that are already there. Neither is recorded in the ledger: sfdt ledger undo covers org configuration, not bulk data writes.


sfdt scratch

Creates, deletes, lists, and pools scratch orgs.

sfdt scratch create --alias feature-x --days 7 sfdt scratch list sfdt scratch delete --alias feature-x sfdt scratch pool --size 3
SubcommandDescription
createCreate a scratch org from scratch.definitionFile
deleteDelete a scratch org
listList active scratch orgs
poolManage a pre-created pool

Options: --alias <name>, --days <n>, --size <n>, --json.


sfdt notify

Pushes a deployment-lifecycle event or an org-health snapshot to configured notification channels (Slack, Microsoft Teams, Google Chat, email, generic webhook, or Grafana Loki).

sfdt notify deploy-success sfdt notify deploy-failure --org production --version 1.5.0 sfdt notify test-failure --message "Coverage dropped below threshold" sfdt notify release-created --version 1.5.0 sfdt notify snapshot --type monitor # push the latest monitor snapshot sfdt notify snapshot --type audit
ArgumentValues
<event>deploy-success, deploy-failure, test-failure, release-created, harness-escalation, snapshot
OptionDescription
--type <kind>For snapshot: audit or monitor (which snapshot to push)
--version <ver>Version label to include
--org <alias>Org alias to display
--message <msg>Custom message body

Configure channels, severity routing, and optional AI executive-summary digests on the Notifications page. audit all / monitor all accept --notify to run and push in one step. The legacy single-Slack config (notifications.slack.webhookUrl with features.notifications: true) is still honored.


sfdt automation

The on/off grid across every kind of Salesforce automation, and the toggles behind it.

sfdt automation list sfdt automation list --type validation-rule sfdt automation disable validation-rule Account.Region_Required --dry-run sfdt automation disable validation-rule Account.Region_Required sfdt automation enable flow Set_Region
SubcommandDescription
listEvery flow, validation rule, duplicate rule, workflow rule and Apex trigger, with its state
enable <type> <name>Turn one component on
disable <type> <name>Turn one component off

The five types do not cost the same to toggle, and the grid says so at the point of use. Flows, validation rules and duplicate rules are Tooling record writes. Workflow rules and Apex triggers need a metadata deploy — and a production deploy runs tests, so toggling a trigger there is a deployment with everything that implies.

Toggling automation changes how the org behaves for every user, immediately. A production org requires --production, and detection fails safe: an org whose sandbox status cannot be read is treated as production. Every change is recorded in the ledger, so sfdt ledger undo restores the prior state.

Common options: --org <alias>, --dry-run, --yes, --production, --json.


sfdt permissions

Object and field access — what is granted, by which profile or permission set, and where the org disagrees with your repository.

sfdt permissions matrix --object Account sfdt permissions drift Account sfdt permissions grant Account.Region__c --parent "Sales Ops" --level edit sfdt permissions revoke Account.SSN__c --parent "Sales Ops" sfdt permissions fix Account --dry-run
SubcommandDescription
matrixWhat each profile and permission set grants
drift <object>Compare org grants against the repository
grant <Object.Field...>Grant field access on a permission set
revoke <Object.Field...>Remove field access
fix <object>Apply the grants your repo declares but the org is missing

Reports what is granted, never “effective”: muting permission sets cannot be queried, and a stronger claim would be an upper bound presented as a fact.

Profiles are refused by name. Salesforce does not permit direct DML on profile-owned permission entries — those must go through the Metadata API, so change them in source and deploy. Refusing up front beats an opaque INSUFFICIENT_ACCESS_OR_READONLY that reads like a problem with your own access.

fix applies only missing-in-org rows. Grants the org has that source does not are deliberately left alone — removing access nobody asked to remove is a different, and riskier, decision.

Common options: --org <alias>, --dry-run, --yes, --production, --json.


sfdt record

Read, edit, or clone a single record, using the same editability model as the Chrome extension’s inspector — so a field refused here is refused for the identical stated reason in the browser.

sfdt record get 001800000000001AAA sfdt record edit 001800000000001AAA --set Name="Acme Corp" --set AnnualRevenue=250000 sfdt record clone 001800000000001AAA --set Name="Acme Corp (copy)"
SubcommandDescription
get <id>Read a record and show which fields are editable, and why the rest are not
edit <id>Update fields (--set Field=Value, repeatable)
clone <id>Create a copy from the record’s createable fields

Non-editable fields are refused locally, by name, before anything reaches the org — formula fields, auto-numbers, and fields your permissions do not cover. A field hidden from you by field-level security is never written as null over a value you were not allowed to see.

A save reports exactly one of three outcomes: saved, nothing was saved, or outcome unknown — the last when a request times out and the write may in fact have committed. Exiting 0 on an unknown outcome would tell a script the change landed.

Common options: --org <alias>, --sobject <name>, --dry-run, --json.


sfdt events

Platform Events and Change Data Capture.

sfdt events list sfdt events tail Order_Placed__e sfdt events tail AccountChangeEvent --replay all sfdt events publish Order_Placed__e --field Order_Id__c=A-1
SubcommandDescription
listEvery subscribable channel, with its Bayeux path
tail <channel>Subscribe and print events as they arrive
publish <Event__e>Publish one platform event

A channel whose query is refused is reported as unchecked — it never silently becomes “your org has none”.

publish fires every subscriber on the channel: flows, Apex triggers, and any external listener. A delivered event cannot be recalled, which is why it is gated going in — a production org requires --production, and there is no undo.

Common options: --org <alias>, --dry-run, --yes, --production, --json.


sfdt packages

Installed package inventory, your own annotations, and version drift between orgs.

sfdt packages list sfdt packages compare --source prod --target uat sfdt packages note ecflc --owner "Platform team" --latest 1.7.0
SubcommandDescription
listInstalled packages with versions and any notes
compareVersion drift between two orgs
note <namespace>Record vendor URL, latest known version, and internal owner

note writes .sfdt/packages.json, a committed file — so an annotation is shared and code-reviewed rather than trapped on one machine. Merges are additive: fields you do not supply are left alone, including keys written by a newer sfdt that this one does not understand.

Common options: --org <alias>, --json.


sfdt history

Shows recent runs from the local run index so org-health, coverage, test, and deploy outcomes can be trended over time instead of only reading the latest snapshot. Every audit, monitor, quality, test, deploy, rollback, and agent-test run is recorded to a compact SQLite index (logs/history.db); audit and monitor also archive full timestamped snapshots under logs/audit-results/ and logs/monitor-results/. Recording is best-effort — a history failure never fails the command.

sfdt history sfdt history --type audit sfdt history --type deploy --limit 50 sfdt history --json
OptionDescription
--type <type>Filter to one run type (e.g. audit, monitor, quality, test-run, deploy, agent-test, agent-fix)
--limit <n>Maximum rows to show (default 30)
--jsonEmit the result as JSON

sfdt versions

Audit Salesforce API versions across local source and the org: which versions your Apex classes/triggers, Flows, LWC, and Aura components are on, compared against the org’s max API version. The local scan reads only the -meta.xml sidecars, so it works fully offline; components whose meta omits <apiVersion> are reported as unspecified (they inherit sourceApiVersion at deploy time) and never counted as outdated.

sfdt versions # local scan + org comparison (default org) sfdt versions --org uat # against a specific org sfdt versions --local-only # fully offline — no org calls sfdt versions --json # full report for scripting / MCP
OptionDescription
--org <alias>Target org (default config.defaultOrg); unreachable orgs degrade to a local-only report
--local-onlySkip the org side even when an org is configured
--adviseAI upgrade advice for local components below the target version (requires features.ai)
--target <version>For --advise: target API version (default: the org max, or the registry max offline)
--type <family>For --advise: restrict to one family — apex | flow | lwc
--jsonEmit the full report (histograms, outliers, thresholds) as JSON

Output shows per-type version histograms (red = below audit.minApiVersion, yellow = behind the org ceiling when audit.apiVersionWarnBehind is set), the org’s max API version and release (e.g. Org max: v67 — Summer '26), and the outlier components with a below-floor / behind-ceiling reason each.

The report is informational (exit 0) — the CI-gating surface is sfdt audit api-versions, which shares the same thresholds. The MCP server exposes the same report as the read-only sfdt_api_versions tool, and the Chrome extension’s api-version-audit feature shows the org-side histograms as a Setup pill.

--advise — registry-grounded AI upgrade advice

With features.ai enabled, sfdt versions --advise explains what upgrading unlocks and what breaks: value, risks, breaking changes in the upgrade path, effort (S/M/L), minimal code changes, an upgrade order across component types, and verification steps (including sfdt quality --api67 when the path crosses v67).

sfdt versions --advise # advise toward the org max (or registry max offline) sfdt versions --advise --target 67 # explicit target version sfdt versions --advise --type apex # only Apex classes/triggers

The advice is grounded by a curated per-version registry shipped with the CLI: the AI may cite version facts only from the registry, and answers “unknown — not in registry” for anything it lacks — it never states version facts from model memory. The advisory is strictly read-only: CLI providers may read component source to ground their analysis (which is how the advice can cite your actual files and lines), but nothing is ever written or auto-fixed. The prompt is user-editable as api-upgrade-advisor in the prompt editor.

Last updated on