Changelog

Release history for the sfp CLI — what changed in each version.

The sfp CLI carries its own version line, separate from sfp server's. Releases are published to npm as @flxbl-io/sfp and in the sfp docker images; see Install sfp. Under codev the CLI runs on the server, at the server's release.

Only releases that change the CLI are listed. A version absent from this page shipped no CLI-facing change. A version marked self-hosted is published to source.flxbl.io, where self-hosted deployments and the sfp docker images take it from.

October 2026

v52.31.1 — October 26, 2026

  • sfp sandbox create with --sourcesandbox, or sourceSandboxName in the definition file, does not send the activation user group, which Salesforce rejects on a clone, and logs that the clone copies the source sandbox's users
  • sfp sandbox update refreshing from a source sandbox does not send --activation-user-group, and clears an activation user group stored on the sandbox's SandboxInfo record, which Salesforce rejects next to a source. Its JSON result includes fromSource

v52.31.0 — October 26, 2026

  • sfp sync org builds the packages it syncs at their version floor: the last known version, or the version promoted in the DevHub when that is higher, with a build number taken from the current time. An unlocked package with no usable floor fails its build with a message to deploy it as source or to establish a baseline, version tag or promoted version first
  • sfp sync org deploys the packages that built when others fail to build. A package whose build failed, or that depends on one that did, is listed as ✗ Build failed with its error, counted as failed in the summary and returned in buildFailures with --json. --reset-tracking resets source tracking only when the sync has no error
  • sfp repo workspace-tree --mode takes incremental or full (default full). incremental builds the checked-out branch head by applying the Git changes since the stored tree's commit, and falls back to a full build when the stored tree is missing, comes from another builder version or from a commit the repository does not have. Either mode publishes the tree only while its commit is still on the branch, and a failed publish fails the command instead of logging a warning
  • sfp repo return-hotfix --return-id creates or recovers the return pull request for a managed hotfix recorded on sfp server
  • sfp org retrieve by-name warns, when it retrieves a Profile, that a profile retrieved on its own carries only profile-level settings and user permissions, and names sfp org profile retrieve for the full profile
  • sfp server scale --agentic-workers (0–10) sizes the hatchet-worker-agentic pool, which runs the workflows named in SFP_AGENTIC_WORKFLOWS with every subprocess in a per-run container, and writes HATCHET_AGENTIC_WORKER_COUNT to .env. When the pool is sized above 0, the command warns if SFP_RUN_LAUNCHER_REPLICAS is not set above 0, as the pool needs the run launcher. Without a flag it reports the agentic pool's configured and running counts with the other pools
  • sfp server start and sfp server update create a run-workspaces volume for the tenant. sfp server update pre-pulls and recreates hatchet-worker-agentic and run-launcher with the other app services, and the code analysis concurrency derived from host memory accounts for agentic workers

v52.30.0 — October 22, 2026 · self-hosted

  • sfp report, sfp cherry-to run and the other commands that run an AI agent address Cloudflare AI Gateway models by their models.dev catalog id, so the approved gateway models are anthropic/claude-sonnet-5 and anthropic/claude-opus-4.8. A dashed id such as anthropic/claude-opus-4-8, passed with --model or configured on the AI integration, is rewritten to the catalog id before the run
  • The sfp docker image and the sfp binaries run on Node.js 22.23.4, the October 2026 Node.js security release

v52.29.3 — October 20, 2026 · self-hosted

  • sfp server update checks hatchet-db, as it already did a self-hosted supabase-db, for databases whose recorded collation version no longer matches the operating system's after a postgres image change, and rebuilds their indexes before migrations run. When hatchet-db has a mismatch, hatchet-engine and hatchet-dashboard are stopped for the reindex and started again with the other services

v52.29.2 — October 18, 2026

  • sfp sandbox create accepts --license-type (Developer, Developer_Pro, Partial or Full, case-insensitive), --template-id, --history-days, --apex-class-id and --auto-activate/--no-auto-activate. A flag takes precedence over the definition file, and the license type is sent to Salesforce in its uppercase form, so a Developer_Pro, Partial or Full request is no longer created as a Developer sandbox. An unknown license type fails the command
  • sfp sandbox create fails before creating anything when the source sandbox is not found in the production org, instead of creating a sandbox from production
  • sfp sandbox reset-passwords authenticates to the sandbox through sfp server when a server is configured, with the new --production-username (-p) naming the production org, and through the DevHub otherwise. It reports the reset as requested for the group members rather than as sent
  • sfp validate org rounds each Apex class's coverage down to a whole percent before checking the 75% per-class minimum for packages without bound test suites, so a class covered at 74.5–74.99% fails validation instead of passing

v52.29.1 — October 15, 2026

  • sfp org drift analyze retrieves a package with up to --large-package-threshold components in one Metadata API retrieve instead of one retrieve per component, and retrieves one package at a time: --package-concurrency defaults to 1 instead of 10. --package-retrieve-timeout (default 45) and --retrieve-timeout (default 150) set, in minutes, the limit for one package's retrieve and for the whole retrieve phase; a package not retrieved within them is reported as retrieve-incomplete
  • sfp release promotes packages when promotePackagesBeforeDeploymentToOrg matches the target org's username, alias or environment name, ignoring case, and requires --devhubalias for every release definition where it matches. When it does not match, the release logs that packages will not be promoted. Aliases that differ only by case and point to different orgs fail the release as an ambiguous promotion target
  • sfp release fails a package whose promotion fails, instead of logging a warning and installing it unpromoted. A package version that is already promoted is still skipped
  • sfp release --json reports versionInOrg as the version the org held before the release, or null when the org held none, instead of the version just installed
  • sfp build skips reporting dropped components to sfp server when its branch resolves to HEAD (a detached checkout), and logs a warning to pass --branch
  • sfp cherry-to run uses the provider's strongest approved model, claude-opus-4-8 on Anthropic, Cloudflare AI Gateway and Google Vertex. A model configured on the AI integration or in the cherry-to policy no longer replaces it
  • sfp server start, sfp server update and sfp server scale derive a memory budget for the Hatchet workers from the host's memory (host memory less 5.5 GiB, and at least half of it), with a PMD heap and a code analysis concurrency sized from it, and write them to derived.env in the tenant directory. SFP_WORKER_MEMORY_BUDGET, SFP_PMD_MAX_HEAP and SFP_CODE_ANALYSIS_MAX_CONCURRENT set in .env take precedence. On Podman with systemd and cgroup v2 the workers share the budget in sfpworkers.slice; elsewhere each worker is capped on its own, with a warning. The commands warn when the host has no swap
  • sfp server pool scratch init logs that a scratch org is no longer active in the DevHub and skips its deletion when cleaning up an org that failed preparation or registration and was already deleted, instead of logging a TypeError

v52.29.0 — October 12, 2026

  • A diff package built by sfp build includes the related components a changed component needs to deploy, even when git does not report them as changed: the parent object of a changed MasterDetail field, every MasterDetail field of a changed object, the objectTranslation of a changed fieldTranslation, the Bot of a changed BotVersion, the schema of an ExternalServiceRegistration, the permission set of a changed decomposed part, and the flowDefinitions of a changed flow from each Translations file in the package. A related component in another package's directory, or outside every package directory, is left out with a warning that names it
  • sfp validate org publishes each Apex test class with its methods to sfp server: duration, class path, and for each method its outcome, duration, declaration line, and the message and stack trace of a failure. A package whose test run found no tests is published as passed with an empty class list
  • sfp server pool monitor restores a pool sandbox that reconciliation marked ERROR when Salesforce lists it as live again, to ASSIGNED, AVAILABLE, ACTIVATING, REQUESTED or PROVISIONING according to its record. When Salesforce returns several sandbox processes for one name, the newest is used. Sandboxes in the new SYNCING status count as available capacity when the monitor computes the replenishment deficit
  • sfp pool fetch prints the server's warning when the sandbox it assigns was taken from a branch sync still in progress. sfp server pool status shows a Syncing row and accepts --filter-status SYNCING, and sfp pool list marks SYNCING sandboxes

v52.28.0 — October 11, 2026

  • sfp apextests resume --partial returns the method results recorded so far, without coverage, when the test run is still in progress, instead of waiting for it to finish. The --json summary reports isComplete, and for an unfinished run runStatus, methodsEnqueued and methodsCompleted. The dashboard outcome of an unfinished run is Failed
  • sfp apextests resume --coverage-max-test-methods skips the reporting-only per-test coverage fetch when the run has more test methods than the limit, and --results-fetch-timeout-minutes sets the time limit for each result fetch attempt. They fall back to SFP_APEX_COVERAGE_MAX_TESTMETHODS and SFP_APEX_RESULTS_FETCH_TIMEOUT_MINUTES, then to 5000 and 10
  • sfp validate org --ref --baseRef and sfp impact releaseconfig --filterByChangesInBranch resolve both refs to commits before computing the merge base. A ref that is empty, starts with -, contains spaces or control characters, or is not found in the repository fails the command with "Git ref ... can't be used"
  • sfp changelog issue and commit links and the workflow run link in the sfp validate org report are built from the repository's GitHub host, taken from GITHUB_SERVER_URL when set, instead of always github.com
  • sfp server callback post sends GitHub comments and issue updates to GITHUB_API_URL when set, otherwise to the API of the GitHub host in GITHUB_SERVER_URL (api.<host> for GHE.com, <host>/api/v3 for GitHub Enterprise Server), instead of always api.github.com
  • sfp report --provider github-copilot uses the token in COPILOT_TOKEN or GITHUB_TOKEN directly and accepts only an OAuth token (gho_) from OpenCode's GitHub Copilot sign-in. Any other token fails with "This token can't be used for GitHub Copilot"
  • sfp report --provider cloudflare-ai-gateway runs with each approved gateway model (anthropic/claude-sonnet-5, anthropic/claude-opus-4-8), including image and PDF input; previously only anthropic/claude-sonnet-5 resolved

v52.27.0 — October 5, 2026

  • A test suite in config/sfp_testsuites.yaml can list the source or diff packages it deploys with under deploy_with. sfp build expands the suites bound to a package into a list of test classes and stores it in the artifact. A binding to a package missing from sfdx-project.json, to a package of another type, or from a suite that selects tests by tags fails the build
  • sfp release, sfp install and sfp validate org deploy a source or diff package with Apex whose artifact carries bound test suites with RunSpecifiedTests and that list of test classes. An explicit testLevel, skipTesting and isOptimizedDeployment: false take precedence over the binding
  • sfp validate org fails a bound package when any Apex class or trigger in its scope is covered below 75%, or below the package's coverage threshold when that is higher, by the bound suites alone. The failure names the classes below the threshold and the suites that ran
  • The sfp validate org report lists only the packages that failed, captioned "N of M failed", and reports a coverage failure only for a package whose coverage verdict failed
  • sfp build and sfp quickbuild skip a package whose build commit is an ancestor of the commit that last published it on the same branch, so the package is not published again under a new version. Other packages in the run still build; skipped packages are listed under "Packages skipped as superseded" and in buildResult.json with status: skipped and skipReason: superseded
  • sfp build and sfp quickbuild accept versionNumber: 0.0.0.LATEST on a dependency to a package of the same project whose version is 0.0.0.NEXT. When the dependency is not part of the build, it resolves to the version last published on the branch as recorded by sfp server, and that exact version is written into the dependent's artifact. The build fails when the published versions cannot be read from sfp server
  • sfp release treats a deployment that stops with an error before every package is attempted as failed: the packages not yet deployed are reported as failed instead of skipped, later release definitions are not deployed, and the command exits non-zero. Writes of deployment information that conflict with a concurrent release are retried
  • sfp repo patch --releasedefinitions <domain>/<release> refuses a release candidate that is aborted or has an artifact without a version. A reference such as core/RC-A.json is fetched from sfp server unless a file exists at that path

September 2026

v52.26.0 — September 30, 2026

  • A diff package with Apex that sets isOptimizedDeployment: false in its descriptor deploys with RunLocalTests in sfp release, sfp install and sfp validate org, instead of RunRelevantTests. skipTesting still takes precedence
  • sfp validate org prints the deployment's TestLevel for each package when tests run as a separate step after the deployment
  • sfp insights logins counts unique users with a single aggregate query, so the report no longer fails for orgs with more users in the 30-day window than one query batch returns
  • sfp server pool scratch init authenticates each scratch org leased from a snapshot pool before preparing it. An org that cannot be authenticated is reported as an error in the pool failure summary and is not deleted

v52.25.0 — September 29, 2026

  • sfp release --quickdeploy <deployId> --payload-fingerprint <fingerprint> commits the validation that sfp release --checkonly returned instead of deploying the package again. Pre-deployment steps are skipped, post-deployment steps run as usual, and the release is recorded as a plain release is. The release is refused when the fetched artifact's fingerprint differs from --payload-fingerprint
  • sfp release --quickdeploy-fallback deploys the package in full when Salesforce rejects the validated deploy id. Without it, a rejected id fails the release and leaves the org unchanged
  • sfp sfdmu run scans the target reports sfdmu writes, prints a records summary, and fails when any row was rejected. --no-failonrowerrors reports rejected rows as a warning without failing. The --json result carries the count under rowFailures
  • sfp sfdmu run, sfp push and sfp install print "Command completed, but N record(s) were rejected by the target org" in place of "Command succeeded." when sfdmu rejected rows
  • sfp publish skips a version already in the registry only when the stored artifact was built from the same commit and package version id. A different source fails the publish with VERSION_COLLISION, an artifact whose source cannot be read fails with IDENTITY_UNVERIFIED, and neither records release metadata, the version baseline or git tags. An artifact the internal registry rejects this way is not published to the external registry
  • sfp server environment lock --hatchet-run-id names the Hatchet run that owns the lock; the server releases the ticket once that run ends, including while it is still queued
  • sfp analyze on a pull request reuses the previous architecture and version-assist verdicts when the net diff is unchanged or the change since the last analysed commit is not significant. Set incrementalReviewEnabled: false in analyze.yaml or the server project configuration to always run a fresh analysis

v52.24.0 — September 27, 2026 · self-hosted

  • sfp release --checkonly validates a single-package domain against the target org with one check-only deployment and returns the validated deploy id. Nothing is committed to the org and no release history is recorded; it cannot be combined with --dryrun
  • sfp release --json reports the deployment error for a failed package instead of null
  • The CLI adds the operating system certificate store to the certificate authorities it trusts, so sfp auth login and sfp server update reach an sfp server whose certificate is issued by a private CA. On Node.js earlier than 22.19, set NODE_EXTRA_CA_CERTS instead
  • sfp auth login --global-auth continues when the server configuration cannot be read, using --sfp-server-url as the sign-in callback base
  • sfp server callback post accepts "comment": { "key": "<key>" } in the context to keep one comment per pull request, updated in place, on GitHub and Azure DevOps
  • sfp validate org reports a run with nothing to deploy as "No changes to validate" instead of "Validation passed". The check still concludes as success
  • sfp insights connected-apps --json returns the org's external client apps under externalClientApps, and under hiddenManagedApps the number of managed connected apps left out without --include-managed. When the org cannot list external client apps, the reason is given under externalClientAppsSkipped
  • sfp insights content lists built-in list views that Salesforce reports without an object as Standard views (no object)

v52.23.1 — September 24, 2026

  • Improvements to check-only validation in sfp validate org
  • sfp validate org now respects dependencyOnDomains
  • sfp validate org --deploywithtests always runs Diff packages with RunRelevantTests
  • sfp sync org --releaseconfig accepts multiple domains and syncs all of them

v52.23.0 — September 23, 2026 · self-hosted

  • sfp validate org builds its validation check from the same report as every other surface, laid out for the platform configured on sfp server
  • sfp validate org no longer writes a second check for a run sfp server already reports
  • Validation results carry per-class coverage for each package
  • sfp server callback post keeps one validation comment per Azure DevOps pull request, updated in place

v52.22.0 — September 23, 2026

  • sfp releasecandidate generate no longer fails for a source-only release configuration with no promotion target
  • String replacement globs match the same way on install, sfp push and sfp pull
  • sfp push reports only the replacements that changed a file, and --json lists the rules that matched nothing under unmatchedRules
  • Non-regex replacement values are applied as written, so a $ in a value is kept

v52.21.2 — September 22, 2026

  • New sfp releasecandidate sync-check lists the domains on a branch whose last release to an environment did not succeed
  • sfp release records a release attempt for each domain on sfp server
  • Improvements to AI credential handling in sfp analyze

v52.21.1 — September 22, 2026

  • Source packages with isOptimizedDeployment: false deploy with RunLocalTests again
  • Fixes to command aliases and topic descriptions for sfp pull, sfp push, sfp sfdmu run, sfp server review-envs and sfp server variable

v52.21.0 — September 21, 2026

  • sfp release --branch <branch> releases the latest published release candidate of each domain on a branch tracked by the project, in place of --releasedefinition or --releasecandidate; the three flags are mutually exclusive. --repository and --sfp-server-url are both required with it, and --domain — repeatable — restricts the release to the domains named. A candidate is eligible only when its domain build succeeded and the candidate was not aborted.
  • sfp release --branch prints the resolved domain, release candidate and commit as a table, then the branch head commit and the domains whose candidate commit differs from it, and lists the domains skipped for want of an eligible candidate. The same resolution is carried under branchResolution in the --json output.
  • sfp release --branch fails before it releases anything when the branch is not among the branches tracked in the project's server configuration, when a --domain is not one of the branch's domains, or when no selected domain has an eligible candidate.

v52.20.1 — September 20, 2026

  • sfp sandbox create sets a sandbox's add-on features from features in the --definition-file definition — an array of strings such as SandboxStorage. When the definition also names a sourceSandboxName, the features recorded on that source sandbox take precedence over the ones in the definition.
  • sfp sandbox create fails when the lookup of sourceSandboxName errors, instead of warning and creating the sandbox without a source. A source sandbox that simply returns no record is still reported as not found, and creation continues without a source.

v52.20.0 — September 20, 2026

  • A source or diff package that carries a Flow in pre-destructive/flows/ or post-destructive/flows/ has that Flow deactivated and every one of its versions deleted through the Tooling API before the metadata deployment, and the Flow is dropped from that deployment. The deletion is not part of the deployment transaction, so it is not undone when the deployment fails. See Destructive changes.
  • A Flow that is absent from the org is recorded as already absent and installation continues. A lookup, deactivation or deletion failure is reported as a warning, that Flow's delete is skipped, and the remaining components are installed. Progress is folded into a Destructive Flows log group that closes with a table of each Flow, whether it was deactivated, how many versions were deleted, and the result.
  • enableFlowDestructiveHandling in a package's sfdx-project.json descriptor turns that handling off for the package, restoring plain metadata deletion. It defaults to true and is independent of enableFlowActivation. The handling is also skipped, and the plain Flow member retained, for a check-only deployment and for a dry-run installation.
  • sfp repo diff --create-package stages two synthetic source packages when the changed packages disagree on enableFlowDestructiveHandling — the metadata from the packages that keep it first, then the opted-out metadata in <name>-flow-optout — and each is deployed separately. Packages that agree still produce one synthetic package.
  • An installation whose components are all removed — a package whose only members were destructive Flows — completes without a metadata deployment rather than submitting an empty one.
  • sfp org flow activate, sfp org flow deactivate and sfp org flow cleanup escape --developername and --namespaceprefix in the SOQL that looks the Flow definition up. An explicitly empty --namespaceprefix now matches only flows with no namespace; it was previously ignored, matching any namespace. Each command's output is folded into a log group.
  • sfp org flow cleanup logs each version as it is deleted, with its position in the run, and names the attempt and the Salesforce error when a deletion is retried.

v52.19.2 — September 19, 2026

  • sfp server update pauses Hatchet worker assignments in bounded cycles instead of holding one pause for the whole drain. --pause-timeout sets the maximum seconds of a single pause, defaulting to 600; when it expires without a confirmed drain the assignments are restored for a 300-second cooldown and a new cycle starts, until the drain is confirmed or --drain-timeout — still 3600 seconds by default — is spent. --pause-timeout must not exceed --drain-timeout, and both flags reject a value below 1.
  • sfp server update updates the tenant files and pre-pulls the new images before it pauses assignments, rather than pre-pulling in parallel with the drain, and recreates Caddy inside the pause window.
  • sfp server update aborts before it stops any service when no drain is confirmed within that budget. Assignments are restored first, and the error names the number of pause cycles, the running and queued workflow counts, and the names of up to 100 running tasks.
  • sfp build continues when a package it has just built is an ordering-only dependency of a package still to be built — a source, diff or data package of the same project, which dependency resolution removes from the dependent's resolved dependency list. Stamping the completed version onto a dependency that is no longer listed previously threw and failed the build.
  • sfp build fails on an invalid preDeploy/replacements.yml in a package: a missing or empty name, glob or pattern, or an environment value that is not a string, boolean or number. It previously logged a warning and built the package without its replacements.
  • Replacement YAML — a package's preDeploy/replacements.yml, and the file passed to sfp push --replacementsoverride — keeps an unquoted date such as 2026-09-17 or timestamp such as 2026-09-17T12:34:56+05:30 as its original text instead of reading it as a date. A boolean or numeric value is applied as its text, and a null, array or object value is a configuration error.
  • A replacement whose value is an empty string is applied, removing the matched text, and an exact org alias takes precedence over default even when the alias value is empty. An empty value was previously treated as no value, leaving the pattern in place. This covers sfp push and the source-package install path that sfp install and sfp release run.
  • sfp push treats a package's preDeploy/replacements.yml, or --replacementsoverride, as authoritative for that package: the replacements entries in sfdx-project.json no longer apply to it as well. A package with no package-level configuration keeps the project-level replacements, and in a push carrying both kinds those project rules are matched against project-relative paths, so a hidden directory in the checkout path no longer suppresses a match.
  • sfp push --replacementsoverride merges the override entries into the package configuration by replacement name, the override's environment values taking precedence, instead of applying both lists.
  • sfp push fails with Unable to prepare push replacements: <reason> when it cannot prepare the replacements. It previously logged a warning and pushed the source without them.
  • sfp push applies package replacements to every file a component carries rather than only its top-level content path, and no longer counts a file in a sibling directory whose name starts with the package directory's name as being inside the package.
  • sfp push removes the temporary conversion context it creates for replacements once the deployment is submitted, including when the conversion or the submission fails.
  • The header line every command prints carries -Build:<number> once when a build number is set, and omits it otherwise. It previously repeated the -Build: label, and printed an empty one when no build number was set.

v52.19.1 — September 17, 2026

  • sfp analyze prints the analysis result as JSON only when --json is set. It previously printed the raw result to stdout alongside the human-readable output whenever a linter named in --fail-on had a blocking finding or could not run.
  • The [AI_RESPONSE] entry carrying a prompt's full response — written by the architecture and version-assist linters of sfp analyze — is logged at debug level rather than info, so it no longer appears in the default console output. It is dispatched straight to the run's logger, so a file or log sink attached to the run still receives it.

v52.19.0 — September 16, 2026

  • sfp server update logs the Hatchet worker-assignment commands it runs over SSH against a remote host, and their output, at debug level rather than info. A command that exits non-zero is still reported at error level.
  • sfp server update names the worker-assignment pause before it runs, and on resume reports how many workers had their assignments restored and how many registrations the restart replaced. That report is printed whether the update finishes or fails.

v52.18.2 — September 15, 2026

  • sfp server callback post --context-id takes the UUID of a callback context held on the server, in place of the inline JSON on --context. The two flags are mutually exclusive and exactly one is required; the command reads the context from the server with the server URL and application token before it posts.
  • sfp server callback post fails before posting on a --context-id that is not a UUID, a --context that is not valid JSON, a context that is not a JSON object, and a context whose username, accessLevel, targetOrg, taskId, taskType or message is not a string.

v52.18.0 — September 15, 2026

  • A package install that composes partial CustomObject metadata — layout assignments from mutators/layout-assignments.yml, and the search-layouts contribution that augments them — carries the target org's object settings into that partial: the supported feature flags, description, gender, startsWith, each targeted record type's description, and the name field's trackHistory and trackFeedHistory. A CustomObject deployment resets allowInChatterGroups, enableActivities and enableReports and clears description, gender and startsWith when they are omitted, so the composed partial previously reset them on install.
  • That composition stops before deployment when the org's CustomObject metadata is incomplete — a missing label or nameField, an AutoNumber name field with no displayFormat, a value that is not a valid boolean, or an enableBulkApi/enableSharing/enableStreamingApi group that is inconsistent — instead of composing a partial that would reset a property.
  • Each setting is written only when the Metadata API version supports it. The version is the one the install deploys with, falling back to the package's apiVersion and then to the component set's.
  • sfp validate org runs its AI error analysis before it publishes the validation result, so the analysis reaches the published result and its markdown as well as the CI check. It previously ran only while the CI check was being created.
  • sfp validate org cancels the AI error analysis at its timeout — three minutes, unless errorAnalysis.timeout in the AI configuration sets another, in milliseconds — and aborts the agent session rather than leaving the request in flight. A transient failure is retried up to three attempts, after 5 and 10 seconds, within that same deadline.
  • The validation markdown records AI error analysis unavailable: <reason> when the analysis produces no insight, where the reason is no credentials, timed out, unparseable response, attempts exhausted or analysis failed.
  • sfp validate org reads its AI configuration from the validation worktree — config/ai-assist.yaml, then the .yml spelling, then config/ai-architecture.yaml and .yml — rather than from the directory the command was started in. The analysis is skipped when the run failed because no changes were detected in the packages to be built, and runs whenever --opencode-server is set.
  • sfp releasecandidate unbundle removes the file when a conflict has no copy of it on the side --conflict-strategy selects, instead of resolving markers in a file that side deleted.
  • sfp releasecandidate unbundle fails when it cannot resolve the new SHA of a cherry-picked commit. It previously logged a warning and continued, leaving the deployment step lineage incomplete.
  • sfp releasecandidate unbundle-analyze counts only re-applied commits in the kept-commit total it prints and returns. A commit that turned out empty after conflict resolution, and was skipped, is no longer counted.
  • sfp auth login and sfp server auth login serve branded sign-in result pages on the CLI's loopback receiver. The failure page escapes the detail returned by the authorization server and names sfp auth login as the command to run again.
  • sfp publish includes the repository and an ISO 8601 timestamp in the webhook events it triggers on sfp server. The repository is read from SFP_REPOSITORY, GITHUB_REPOSITORY or GITLAB_REPOSITORY, in that order.

v52.17.0 — September 11, 2026

  • sfp publish --pushgittag pushes the tags for all published packages in a single git push, instead of one push per package. A transient failure — a dropped connection, an unresolved host, an HTTP 5xx — is retried three times, after 2, 5 and 15 seconds. An authentication, permission, protected-tag or ruleset rejection is not retried.
  • sfp publish completes when the tag push does not, instead of failing the run. It lists the tags that still need pushing and the git push origin refs/tags/… command that pushes them, with remote URLs and credentials stripped from the reported error, and leaves the --gittaglimit and --gittagage cleanup for that retry.
  • sfp releasecandidate unbundle --source-branch defaults to the branch recorded on the release candidate, falling back to main when the candidate records none. It previously always defaulted to main. An explicit value still takes precedence.
  • sfp releasecandidate unbundle removes its temporary worktree when the run fails as well as when it succeeds, and raises a failure through the command's own error handling — so --json reports it — instead of exiting immediately.
  • sfp releasecandidate unbundle reports how many manual deployment steps were re-anchored onto the rewritten branch and how many were flagged for review. The command fails when the server cannot record that anchor migration, after the branch has been pushed.

v52.16.1 — September 10, 2026

  • sfp server update pauses Hatchet worker assignments before it drains, then waits only for workflows that occupy a worker slot. Queued tasks are no longer waited on; they stay pending and run once the workers return. The drain is checked again after the image pre-pull and the Caddy recreation, and the paused workers are restored when the update finishes or fails.
  • sfp server update aborts before it stops any service when the drain fails or the running-workflow count cannot be read. It previously logged a warning and continued with the update. --force still skips both the pause and the drain, and --drain-timeout still bounds the wait, in seconds, defaulting to 3600.
  • sfp scratch delete completes without error when the Dev Hub holds no active scratch org record for the username. The lookup previously raised No ActiveScratchOrg found for username <username>, which the command reported as a missing org or a permissions failure.

v52.16.0 — September 8, 2026

  • sfp org login --server --default-devhub accepts --repository (alias --repo) to authenticate with the DevHub selected for that project, and fails when the server resolves the DevHub from anywhere else. sfp server org get-default-devhub takes the same flag. Both name where the DevHub came from — the project's default DevHub, a legacy project registration, or the tenant default.
  • sfp scratch login without --devhub-username has the server resolve the DevHub that owns the scratch org, instead of trying the tenant default DevHub and then each registered DevHub in turn.
  • sfp sandbox login without --production-username has the server resolve the production org bound to the sandbox, instead of trying each registered production org in turn. A sandbox registered without a production connection logs in, and the output omits the Production Org line.
  • sfp server pool monitor names the pool it is reconciling when it reads sandbox state from Salesforce, so the state covers that pool's own instances rather than every sandbox under the Dev Hub.
  • sfp scratch delete fails when the Dev Hub rejects the deletion, instead of reporting success. A username with no active scratch org record in the Dev Hub is left alone.
  • --passphrase on the SSH-based server commands — sfp server init, start, stop, status, logs, scale and update — is passed to the SSH connection, so an encrypted --identity-file can be used. The key is read when the flags are parsed and is no longer written into the lifecycle configuration that debug logging serialises.
  • Those same commands report an SFTP error raised while checking for a directory on the remote host, instead of treating the directory as absent.

v52.15.1 — September 7, 2026

  • sfp server update and sfp server init copy the Supabase schema to a remote host through a temporary archive that is extracted and then removed. Removing it now tolerates an archive that is already gone, so a repeated or concurrent run against the same tenant directory no longer fails after the extraction has succeeded.

v52.15.0 — September 4, 2026

  • sfp auth login and sfp server auth login sign in to flxbl cloud when no server URL is given, through the global auth service over OAuth 2.1 with PKCE and a loopback receiver bound to 127.0.0.1. --sfp-server-url no longer defaults to http://localhost:3029.
  • sfp auth login --sfp-server-url reads the server's /sfp/api/config before signing in: a server that reports itself as self-hosted routes the sign-in to the auth service it publishes, and an unreachable URL fails before a browser opens. --global-auth and --no-global-auth force either service and no longer carry a default.
  • sfp auth login prints the sign-in URL before it opens a browser, so a session where no browser opens can still complete the sign-in. On the self-hosted path the browser is redirected to the server's hosted /auth/callback page, which shows an sfp1_ login code to paste into the terminal when it cannot reach the CLI's loopback.
  • sfp install and sfp release group the output of each pre- and post-deployer and of the preDeployment and postDeployment scripts, and keep the component checksum skip pre-fetch lines inside the eligibility group.

v52.14.3 — September 2, 2026

  • sfp analyze --output-format github renders code-analyzer and architecture findings as a Markdown list — severity, rule, location and gate on the first line, the message on the next — instead of an HTML table. --output-format markdown keeps its tables.
  • sfp analyze and sfp project version suggest pass the architecture and version-assist instructions to the AI as its system prompt, rather than prepending them to the pull request content being analysed. The architecture instructions return the empty JSON result the parser reads when there is no architecturally significant change, in place of a plain sentence.

v52.14.2 — September 2, 2026

  • sfp project preflight reports a repository with no sfdx-project.json, or one that cannot be parsed, as a not-configured status with the cause listed under issues. Previously the read error aborted the run.

v52.14.1 — September 2, 2026

  • sfp cascade merge-assist no longer stops responding when the AI agent asks to access a directory outside the working tree. The request is answered instead of left pending.

v52.14.0 — September 1, 2026

  • sfp validate grounds its AI analysis of a failure. Commands it suggests are checked against the CLI's own command set, and browserforce settings are reported as org-UI settings rather than as CLI flags.
  • A package build reports a missing Package2 registration in the Dev Hub as that, instead of as a generic creation failure.
  • Repository and npm-registry calls to sfp server report the server's own error message instead of a generic substitute.

August 2026

v52.12.0 — August 30, 2026

  • sfp analyze runs the version-assist AI linter only when it is asked for. --version-assist runs it, --no-version-assist keeps it off even when the project enables it, and with neither flag it runs only when the server project settings explicitly enable it.
  • A package install that fails on a transport error — a dropped connection, DNS, or TLS failure — names the underlying cause instead of reporting fetch failed.
  • sfp server scale sizes both Hatchet worker pools. --workers sets the general pool and sizes the long-running pool proportionally; --longrunning-workers sets the long-running pool explicitly; --drain-timeout bounds the wait for in-flight work, and --force scales down without draining.

v52.10.2 — August 27, 2026

  • sfp analyze reports a linter that was skipped as skipped, instead of reporting it as a pass.

v52.10.0 — August 26, 2026

  • sfp validate org --waittime sets the metadata deployment wait for each package, in minutes. Defaults to 120.
  • sfp org drift analyze --max-ai-findings skips the AI review when the mechanical candidate count exceeds the threshold. Defaults to 50.
  • sfp apextests resume bounds result fetching, so a large-org run stores its results instead of abandoning them on a timeout.
  • sfp server init creates the admin team, so a newly initialised admin can manage the organisation.

v52.9.3 — August 25, 2026

  • Dependency resolution ignores source package dependencies declared inside the same project.

On this page