Foreman›Docs›Salesforce pack›What the pack adds
What the pack adds
Salesforce pack · page 1 of 9
Agents, traits, pinned skills, the sf wrapper and the ship steps the pack turns on, and what is still unproven.
Preview. The Salesforce pack ships in Foreman 0.11.0 as a preview: its release paths pass their own tests, but no story has yet shipped through them on a live org. Treat the Gearset path as experimental.
The Salesforce pack is what Foreman adds to a project that has sfdx-project.json: six agents that know Salesforce, a set of traits (standing rules) for them, the official Salesforce skills pinned to one version, an sf home of its own for every story session, a build org per slot, and release paths that deploy to sandboxes and never to production. This page is the map. Read it before you put Foreman on a Salesforce project; the pages after it go into each part.
Preview status: what is proven and what is not
The pack ships in Foreman 0.11.0 as a preview. Its three release paths (sf, ci and gearset) pass their own tests, but no story has yet shipped through them on a live org, and the Gearset path has not run against a live Gearset pipeline: Foreman’s own Gearset access ended before that proof could happen. Everything else in 0.10.0 has been running Foreman’s own backlog for weeks; the pack has not.
What that means in practice:
- The config check, the production block, the isolated
sfhome, the sandbox pool, the scratch org flow, the ship steps and the doctor checks all have tests in Foreman’s own suite. None of them has yet taken a real story from a sandbox to a QA org. - The Gearset screen on the Set up tab, the
gearset-prandgearset-promotesteps and the Gearset doctor checks are built against Gearset’s Reporting API as documented. They have not been run against a live pipeline. - Start on a sandbox you can refresh, keep
stopAtat your first stage, and readforeman doctorand the release’s steps closely the first few times. Release safety explains what halts and what rolls back; Stages and release paths explains the three paths.
Treat the pack as experimental until a release says otherwise.
Turning the pack on
A project turns the pack on with "pack": "salesforce" in foreman.config.json. There are three ways to get there:
/foreman:initon a project withsfdx-project.jsonat the root asks the pack’s questions first and writes thesalesforceblock from your answers. Set up on Salesforce lists every question.- On the dashboard, Set up › This project offers the Salesforce pack as a switch when
sfdx-project.jsonis there. Areas that are off show one line saying why, with Turn on. - By hand: add
"pack": "salesforce"and asalesforceblock. The salesforce block has every key.
pack must name a pack Foreman has; salesforce is the only one in 0.11.0. The pack’s own top-level key, salesforce, is then allowed and checked by the pack. A project whose stories come from Salesforce Cases (stories.adapter: "salesforce") needs the pack on.
What Foreman finds in the project
foreman init and the Set up tab read sfdx-project.json to suggest the block. Foreman reports the package folders (and which is the default), sourceApiVersion, the LWC tools in package.json (Jest through @salesforce/sfdx-lwc-jest or a script that runs it, ESLint through eslint or any @salesforce/eslint-* package, Prettier), whether OmniStudio metadata is in the source (a folder named omniScripts, omniIntegrationProcedures, omniDataTransforms or omniUiCard) and whether Agentforce metadata is (aiAuthoringBundles, bots, genAiPlannerBundles, genAiPlugins or genAiFunctions). It walks each package folder up to 8 levels down, skips node_modules and dot folders, and never reads a package folder that lies outside the project. A broken sfdx-project.json is reported and init carries on.
What the machine needs
The pack needs openssl on the machine, for the sign-in key. It also needs the Salesforce CLI and two of its plugins, at these minimum versions, which the doctor’s salesforce tools check reads from sf plugins --core:
| Name | What it is for | Minimum version |
|---|---|---|
@salesforce/cli |
every deploy, query and test | 2.0.0 |
sfdx-git-delta |
the story’s delta and the clean-up of a build org | 6.0.0 |
@salesforce/plugin-code-analyzer |
Code Analyzer in the tester and the code reviewer | 5.0.0 |
In the cloud, the Foreman runner image has a -salesforce variant that carries these tools; Foreman picks it when the pack is on. See Run in the cloud.
What the pack fills in
With the pack on, Foreman puts a layer of defaults between its own and your file. You write none of this; foreman config show prints the result.
| Name | What the pack sets |
|---|---|
roles.architect |
foreman:sf-architect |
roles.builders |
admin (foreman:sf-admin, declarative work), developer (foreman:sf-developer, Apex or LWC), and agentforce (foreman:sf-agentforce) unless salesforce.agentforce is off |
roles.tester |
foreman:sf-tester |
roles.reviewers |
compliance (foreman:compliance-reviewer), security (foreman:security-reviewer), code (foreman:sf-code-reviewer) |
install |
npm ci when package-lock.json is present; it creates node_modules |
checks |
sf project deploy start --dry-run --test-level <testLevel.validate> --wait 60 when **/*.{cls,trigger,xml} changed; npm run lint --if-present when **/{lwc,aura}/** changed; npm run test:unit --if-present when **/lwc/** changed. None runs always, so foreman doctor never reaches an org through a check |
ship.steps |
for sf and ci: sf-org-guard, merge-main, sf-delta, push, pr, ci, sf-validate, mergeable-recheck, merge, then per stage up to stopAt: sf-deploy-<stage> and sf-verify-<stage> (sf) or ci-deploy-watch-<stage> (ci). For gearset: sf-org-guard, merge-main, sf-delta, push, gearset-pr, sf-validate, then gearset-promote-<stage> per stage |
ship.ci.required |
an empty list: every check on the pull request must pass |
ship.pr.into |
stage 1’s branch, when it has one |
ship.merge.keepBranch |
true when the release is gearset, or a stage after the first (up to stopAt) has a branch of its own |
ship.rollback |
foreman sf rollback "$FOREMAN_STORY" with a time limit of 3600 seconds, on the sf path only. A rollback deploy runs tests and can take 30 minutes |
env.adapter |
sandbox-pool, or scratch when salesforce.build is a scratch definition |
A ship block in your own file replaces the pack’s as a whole, including the pull request target, so leave ship out unless you mean to replace all of it. If you do write ship.steps, sf-org-guard must come before sf-validate and every sf-deploy-<stage>; the config check refuses anything else.
The layout also sets how many slots (parallel story workers) you may run: one per build org, and only one when stage 1’s org is also a build org. Build orgs has the detail; Slots has the general rule.
The Salesforce agents
A story goes through an architect, a builder, a tester and reviewers; Agents and traits describes the pipeline. The pack replaces the architect, the builders and the tester with Salesforce ones and adds a Salesforce code reviewer beside the two core reviewers. All six share a few rules about the org: the slot’s build org is the worktree’s default org, so they give no target-org flag; they may read its schema with sf sobject describe and sf data query; they never deploy by hand, never run sf project retrieve, org login or org logout, never create, update or delete records, and use sf, never sfdx.
sf-architect designs one story before anyone builds it and writes no files. It reads the story, the project’s metadata and the slot org’s schema, and first decides whether the story can be built now: it blocks when a field has no type or picklist values, a trigger has no object or events, a Lightning Web Component has no description of what it shows, or when only you can supply something. Its design names every file under the package folder with its -meta.xml, the API version from sfdx-project.json, the field-level security and page layout entry for every new field (the one thing it adds unasked), the Apex test classes and what each proves, and a done_when check, normally the dry-run deploy with the story’s tests. It then picks the builder: admin for declarative work, developer for any Apex or LWC, the Agentforce builder when that is the work, and developer for OmniStudio work unless you add an OmniStudio builder of your own.
sf-admin builds declarative stories as metadata source files: objects, fields, validation rules, page layouts, permission sets, Flows, Lightning pages, tabs, applications and list views. It writes the tests first, implements until they pass, runs the brief’s quick checks through foreman checks --changed --quick, and loads the pinned skill for each metadata type before it writes it.
sf-developer builds stories with Apex or Lightning Web Components, plus the metadata that code needs. It works the same way, with the Apex and LWC skills, and also writes the fields and permission sets its code needs.
sf-tester decides whether the story works. It runs every check fresh with foreman checks --changed, dry-runs the deploy with RunSpecifiedTests (the story’s test classes plus every test class that names a class or trigger the change touches), reads coverage per class from the JSON result, runs LWC Jest and Code Analyzer, previews changed agents and verifies the story’s “Done when” line by doing what it says. Before the dry run it asks foreman sf baseline --story which failures the org already had, so an inherited failure is a minor finding, not a blocker. It approves only with no blocker and no major finding.
sf-code-reviewer runs beside the compliance and security reviewers once the tester approves. It reviews every changed Apex, LWC, Flow, metadata, OmniStudio and Agent Script file against Salesforce practice, runs Code Analyzer with the Recommended rules on the changed files (severity 1 is a blocker, 2 a major, 3 to 5 minor), and cites a file and line for every finding. It reports; it does not fix.
sf-agentforce builds Agentforce stories: the agent’s Agent Script bundle, the actions it calls, the Apex or Flows behind them, and an eval spec for each agent the story changes. It is listed as a builder unless salesforce.agentforce is off. Agentforce and OmniStudio covers how agents are published, activated and evaluated.
There is no OmniStudio builder in 0.11.0, whatever salesforce.omnistudio says. To use your own, add it under roles.builders with a use line.
The pack’s traits
A trait is a short rule Foreman puts in front of an agent for every story. The pack brings three trait files, and they go before your project’s own traits, so yours win when they disagree. Do not add them again with foreman traits add.
For every agent: use sf, never sfdx; the slot org is the default org, so no target-org flag, except the tester’s dry run under its own rules; never org login, org logout, sf project retrieve, deploy quick, --ignore-conflicts or --ignore-errors; never create, update or delete records; take the API version from sfdx-project.json; production is never a target.
For the security reviewer: Apex enforces CRUD and field-level security (WITH USER_MODE on queries, AccessLevel.USER_MODE or Security.stripInaccessible on DML); classes are with sharing unless a comment says why not; no SOQL built by concatenating input; nothing new exposed to guest users unless the story asks; secrets and endpoints in Named Credentials only.
For the tester: the dry run’s org comes from salesforce.test (the slot org with no flag when it is build, else --target-org <that stage's alias> on the dry run only); run foreman sf baseline --story first and never --refresh; dry-run with RunSpecifiedTests; a changed class below salesforce.coverage.floor is a blocker and below salesforce.coverage.target a major; a test class that fails with UNABLE_TO_LOCK_ROW is re-run once on its own and reported as minor if it then passes; never seed data into an org.
Pinned skills
The agents work from the official Salesforce skills, installed in the project at one pinned version so every story uses the same ones. salesforce.skills names the source and the tag: by default forcedotcom/sf-skills at tag 1.66.0.
foreman sf skills installs them the way the npx skills CLI does, so either tool can read what the other wrote:
.agents/skills/<name>/holds each skill’s files, copied from the source at the pinned tag. Only folders underskills/with aSKILL.mdcount;.git,node_modulesand symlinks are never copied..claude/skills/<name>is a relative symlink to../../.agents/skills/<name>.skills-lock.jsonrecords each skill as{ source, sourceType, ref, commit, skillPath, computedHash }, version 1, sorted.commitis the commit the tag pointed at; it is Foreman’s own field.
Commit all three. Foreman owns skills-lock.json: a new install replaces the skills it lists, removes the ones a new tag dropped, and refuses to overwrite a skill folder it did not install (<path> is not from <source>; move it or remove it). Nothing is written into the project until every check has passed, and nothing is copied into the plugin itself.
source can be owner/repo on GitHub, an https:// or file:// URL, or an absolute path. A URL that holds a user name, a token or a query string is refused before any git call, and the refusal does not repeat it; use a git credential helper instead. Foreman gives git ls-remote 60 seconds and the shallow clone 300 seconds. When the tag now points at a different commit than the lock recorded for the same source and tag, the command still installs but warns, with the old commit, because tags are meant not to move.
Each agent names the skills it must have in its frontmatter: platform-soql-query (architect), platform-metadata-api-context-get and platform-permission-set-generate (admin), platform-apex-generate and platform-apex-test-generate (developer), agentforce-generate, agentforce-test, platform-apex-generate, platform-apex-test-generate and automation-flow-generate (Agentforce builder), platform-apex-test-run and dx-code-analyzer-run (tester), dx-code-analyzer-run (code reviewer). The agents load more by name as the work needs them, such as experience-lwc-generate, automation-flow-generate, platform-docs-get and experience-lwc-security-validate. Two doctor checks keep this honest: salesforce skills lock (the lock pins the configured source and tag, and every skill is installed, linked and unchanged) and salesforce skills named (every skill an agent’s frontmatter names is in the lock). See Doctor checks.
The isolated sf home
Story sessions never see your own sf logins. Foreman keeps an sf home of its own, FOREMAN_SF_HOME, by default ~/.config/foreman/sf-home, holding only the orgs in salesforce.orgs: the build orgs, the stage orgs, in scratch mode the Dev Hub and each story’s own scratch org, and any org marked "production": true. You sign each org in there once, on the Set up tab; Foreman never touches ~/.sf or ~/.sfdx. The folder is made at mode 700. If you set FOREMAN_SF_HOME yourself it must be an absolute path: ~ is not expanded there, and a relative path is refused rather than resolved.
Before each run’s sessions start, Foreman writes two wrapper scripts, sf and sfdx, into <home>/.foreman/bin and puts that folder first on every session’s PATH. Each session also gets FOREMAN_SF_HOME and SF_DISABLE_TELEMETRY=true in its environment. The wrapper refuses to run when FOREMAN_SF_HOME is not set, then sets HOME to the isolated home, SF_USE_GENERIC_UNIX_KEYCHAIN=true (without it sf cannot reach the macOS keychain from another home and saves no login), SF_DISABLE_TELEMETRY=true and SF_DATA_DIR to your real sf data folder, so plugins such as sfdx-git-delta and Code Analyzer are still found, and runs the real sf it found on PATH at set-up. When salesforce.orgs marks a production org, the wrapper also unsets SF_TEMP_SHOW_SECRETS and runs the production check first, which refuses any command off the production allow-list that would reach that org, however the org is named. Production stays yours has the allow-list.
At the same time Foreman checks the home’s contents with sf org list, which contacts no org. An org in the home that is not in salesforce.orgs (a stray) stops the run before any query, with a logout line you can run as printed. Every listed org is then asked SELECT Id, IsSandbox FROM Organization: it must be a sandbox with the org ID the config gives it, or a production org the config marks so, with that org ID. In scratch mode a story’s scratch org is accepted only while its record names the configured Dev Hub and the Dev Hub lists it as an active scratch org. A reason never names an org by its username, only by alias or org ID.
Two more things are set on each session. The salesforce-development Claude Code plugin is turned off, because it cannot see the orgs in this home and would deny every deploy; the doctor’s salesforce plugin check only warns when it is on for you. And the Read tool is denied on ~/.config/foreman/sf, where the sign-in keys live, while the Bash guard denies a command that names that folder.
When an org answers a sign-in with a login-rate error, Foreman records a cool-down for it in <home>/.foreman/cooldown and makes no sf call to that org for an hour (3,600,000 milliseconds), because retrying can lock the user out. Foreman’s own commands, the doctor and the ship steps all run sf through the same home, so they check the logins the sessions will see. The doctor’s salesforce sf isolation check runs the same verdict on demand.
Was this page useful? Something missing or wrong?Email us and say which section.