agentleFS
grzmolgrzmol/vibe-force/skills/sf-process-builder-migration/SKILL.md

sf-process-builder-migration

Skill2 starsChanged 2 months agoMITView on GitHub

Migrate retired Process Builder processes to record-triggered Flows - inventory what is still active, read a process without loading its XML, map criteria nodes to entry conditions and Decisions, map action groups to before-save assignments or after-save elements, turn scheduled actions into scheduled paths, keep the start-of-process value semantics and the reevaluation option honest, and cut over in two deploys. Use when a project still has active processes, when a process and a flow fight over the same field, when planning a Process Builder decommission, or when the Migrate to Flow tool reports a partial migration.

The file

We split this skill into the rules it gives an agent

1 rule. About 0 are common, 0 are distinctive, and 1 is very specific to this project.

  • ≈0

    Common · estimate

    Many files like this have a rule of this kind.

  • ≈0

    Distinctive · estimate

    This author's own choices. Worth a look.

  • 1

    Very specific

    Tied to their project's names, files or tools. Probably skip.

  • Common
  • Distinctive
  • Very specific
  1. Very specific:

    Start-of-process values: When a process continues to the next criteria node - the EVALUATE THE NEXT CRITERIA option - the next node …

    line 158

≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.

Keep what fits and drop the rest. Your version, ready for your agents.
Files
SKILL.md

Process Builder Migration

When to use

  • The org still has active processes. Salesforce blocked creating processes in Summer '23 and ended support for Process Builder and Workflow Rules on 31 December 2025. Existing processes still execute, unsupported.
  • A field is written by both a process and a flow, or two processes write it in step 13 of the save order, where no order is guaranteed.
  • A story touches an object that a process automates: migrate that concern first, then build.
  • /vf-check analyzer or an audit (sf-technical-debt-audit) reports active processes.

A process is not its own metadata type. It is a Flow whose processType is Workflow, stored in flows/ with a .flow-meta.xml suffix like every other flow. So a repository with "no Process Builder directory" can still be full of processes, and the retrieve command is Flow, not Process.

processTypeWhat it isMigratable
WorkflowRecord change process - starts when a record is created or editedYes, this skill
InvocableProcessInvoked by another process or the Invocable Actions REST resourceNot by the Setup tool; rebuild as a subflow or an autolaunched flow
CustomEventEvent process, started by a platform event messageNot by the Setup tool; rebuild as a platform event-triggered flow
anything elseAlready a flowNothing to migrate

Decision table: which route for which process

SituationRouteWhy
Whole process, mixed actions, you want it off Process Builder todayMigrate to Flow in SetupIt migrates the whole process as an after-save flow and reports what needs review
A criteria node whose actions only stamp fields on the triggering record/vf-migrate-process convertEmits a before-save flow: no extra DML, no second save
Process with scheduled actionsMigrate to Flow, one outcome at a timeScheduled actions migrate only when you select the single criteria they belong to
Invocable or event processRebuild by handOut of scope for the Setup tool
Criteria with related-record fields, or a formula with a cross-object referenceRebuild by handField traversals are unsupported; a cross-object formula reference cannot migrate at all
Process plus an Apex trigger on the same objectDecide one owner firstMigrating an ordering bug produces a flow with the same ordering bug
Process nobody can explainRead the org, not the fileFlowDefinitionView, debug logs, then this skill

The Setup tool and this plugin's converter answer different questions. The Setup tool is the fastest way to a working after-save flow. /vf-migrate-process is the way to a cheap before-save flow for the nodes that qualify, and an explicit list of what does not.

1. Inventory before touching anything

# Every process and flow the org runs, with its type and status
sf data query --use-tooling-api --target-org <alias> \
  --query "SELECT ApiName, Label, ProcessType, TriggerType, Status, VersionNumber FROM FlowDefinitionView WHERE ProcessType IN ('Workflow','InvocableProcess','CustomEvent')"

# Pull them into source; the metadata type is Flow
sf project retrieve start --metadata Flow:Case_triage --target-org <alias>

# What else automates the same object
sf data query --use-tooling-api --target-org <alias> \
  --query "SELECT Name, TableEnumOrId, Status FROM ApexTrigger WHERE TableEnumOrId = 'Case'"

Record the answer in .vibeforce/state/contract.md: object, process name, who else writes those fields. A migration that does not know the other writers is a rewrite with extra steps.

2. Read the process without reading the XML

A process file is large and almost entirely canvas coordinates and processMetadataValues. Reading it whole costs tens of thousands of tokens and tells you nothing the plan does not.

node "$CLAUDE_PLUGIN_ROOT/scripts/vf-process-to-flow.js" plan \
  force-app/main/default/flows/Case_triage.flow-meta.xml

The plan prints, per criteria node: the conditions as flow entry conditions would express them, the field writes that can become before-save assignments, the actions that must become after-save elements, the scheduled actions, and every reason the node cannot be converted mechanically. It quotes no XML. Exit 1 means the file does not convert - the wrong processType, an unreadable trigger, no reachable criteria node.

The command wrapper is /vf-migrate-process; the guard that denies whole-file reads of big metadata is described in sf-project-structure.

3. Target architecture, decided before any conversion

One process usually becomes more than one flow, because a process mixes work that belongs on different sides of the save.

flowchart TD
    P["Process, N criteria nodes"] --> C{"Per criteria node"}
    C --> F{"Actions only write<br/>the triggering record?"}
    F -- yes --> B["Before-save flow<br/>one Assignment on $Record"]
    F -- no --> A{"Time-based?"}
    A -- no --> S["After-save flow<br/>Update Records grouped per object"]
    A -- yes --> T["After-save flow<br/>+ scheduledPaths"]

Rules that decide the shape:

  1. Field writes on the triggering record go before save. A before-save flow assigns to $Record. An Update Records element on the triggering record saves the record a second time, which is exactly the cost the migration is supposed to remove.
  2. One Update Records element per target object, not per field. A process with four updates to the same Account is one element with four inputAssignments.
  3. One flow per object per timing, not one flow per criteria node, once you are past the mechanical conversion. Entry conditions and a Decision inside the flow cost less than five flows racing in step 14.
  4. Never both. The process is deactivated at the end of the migration, not kept "just in case".

4. Criteria nodes to entry conditions

Process criteriaFlowNotes
Conditions are met, AND / ORstart.filters + filterLogic and / orStraight mapping
Conditions are met, custom logic (1 AND (2 OR 3))filterLogic with the same stringFlow accepts the logic string
No criteria - just execute the actionsNo filters at allThe flow runs on every save that matches the trigger
Formula evaluates to trueEntry formula, or a DecisionReferences must be rewritten from [Object].Field / myVariable_current.Field to {!$Record.Field}
Advanced: only when the record is created or edited to meet criteriadoesRequireRecordChangedToMeetCriteria trueSame intent, same wording in the metadata
myVariable_old.Field{!$Record__Prior.Field} in a Decision or an entry formulaEntry conditions cannot read prior values
Related-record field (myVariable_current.Account.Industry)Get Records + DecisionEntry conditions filter the triggering record only

Operators are where a conversion quietly breaks. FlowRecordFilter (entry conditions) accepts only EqualTo, NotEqualTo, GreaterThan, LessThan, GreaterThanOrEqualTo, LessThanOrEqualTo, StartsWith, EndsWith, Contains, IsNull. A process condition may use any FlowComparisonOperator, including IsChanged, WasSet and In, which have no entry-condition form: rebuild them as a Decision, or as an entry formula comparing {!$Record.F} with {!$Record__Prior.F}.

5. Action groups to flow elements

Process actionFlow elementMigrate to Flow tool
Update Records, triggering record, literal or same-record referenceAssignment on $Record, before saveMigrates as after-save; optimise by hand
Update Records, related recordsUpdate Records, after save, grouped per objectSupported
Create a RecordCreate Records, after saveSupported
Email AlertsAction element, after saveSupported
ApexAction element (@InvocableMethod)Supported
FlowsSubflow, same transactionSupported, but redesign anything with a callout or a pause as an asynchronous path
Post to Chatter, Quick Actions, Submit for Approval, Send Custom Notification, Send Surveys, Quip, Live MessageSame element, needs configuration after migrationPartial
Processes (invocable)Subflow or autolaunched flowUnsupported
Scheduled actionsscheduledPaths on an after-save flowOnly when you migrate the single criteria that owns them

sf-flow-automation owns the element-level detail of the flow you are building; sf-apex-development owns the invocable class behind an Apex action.

6. Scheduled actions to scheduled paths

ProcessFlow
Scheduled action, N days/hours after the record date fieldscheduledPaths entry with timeSource RecordField, recordField, offsetNumber, offsetUnit
Scheduled action N hours after the triggering eventtimeSource RecordTriggerEvent with the offset
Pending actions already queued in the orgThe migrated flow deletes the process's pending actions at run time and re-queues them on the right path, or cancels them when the record no longer qualifies

A time-based process migrates one outcome per flow. Select several criteria in the Setup tool and no scheduled action is migrated at all. Monitor the queue in Setup before and after: pending items that silently disappear are the failure mode.

7. The two semantics a mechanical conversion gets wrong

Start-of-process values. When a process continues to the next criteria node - the EVALUATE THE NEXT CRITERIA option - the next node evaluates the values the record had at the beginning of the process. A flow does the opposite: a Decision after an Assignment sees the value the Assignment just wrote. Chained criteria therefore cannot be split into independent flows, or turned into a straight Decision chain, without deciding which value each branch should see. The converter blocks these nodes instead of emitting them.

Reevaluation. A process may be configured to evaluate the same record up to five additional times in a single save. Flows have no equivalent, and Salesforce documents that a migrated process with recursion is evaluated only once. If the process relied on reevaluating - ISNEW, PRIORVALUE or a field the process itself changes - the migrated flow is a different automation and needs a deliberate test, not a diff.

8. Cutover, in two deploys

# 1. plan, then convert what converts
node "$CLAUDE_PLUGIN_ROOT/scripts/vf-process-to-flow.js" plan <process file>
node "$CLAUDE_PLUGIN_ROOT/scripts/vf-process-to-flow.js" convert <process file> --criteria 'myRule_1'

# 2. build the after-save half by hand from the plan's after-save lines

# 3. shape and validate before an org sees it
node "$CLAUDE_PLUGIN_ROOT/scripts/checks/vf-check.mjs" local --files <flow file>
sf project deploy validate --source-dir <flow file> --target-org <alias>

# 4. deploy the flows, activate them, verify behaviour against real records
# 5. only then, in a second deploy, deactivate the process

The order is not negotiable. Deactivating first leaves a window with no automation. Doing both in one deploy leaves no way to roll back one half. Keeping both active writes the same field twice in one save, in an order the platform does not define.

Anti-patterns

One flow per criteria node, all after-save, Update Records on the triggering record

<!-- WRONG: the record is saved a second time on every trigger -->
<recordUpdates>
    <name>Stamp_the_case</name>
    <inputReference>$Record</inputReference>
    <inputAssignments>
        <field>Priority</field>
        <value><stringValue>High</stringValue></value>
    </inputAssignments>
</recordUpdates>
<!-- RIGHT: before save, one Assignment, no DML -->
<assignments>
    <name>Set_Fields</name>
    <assignmentItems>
        <assignToReference>$Record.Priority</assignToReference>
        <operator>Assign</operator>
        <value><stringValue>High</stringValue></value>
    </assignmentItems>
</assignments>

Deploying the generated flow under the process's own API name

A Flow deployed with the process's fullName becomes a new version of the process, not a new flow. The converter refuses the name collision; do not work around it with --flow-name set to the same value.

Turning a criteria chain into a Decision chain and calling it equivalent

The second outcome now sees fields the first outcome wrote. See section 7. Either keep the chain in one flow and decide each branch's inputs deliberately, or split it and re-derive each entry condition.

Copying a process formula into a flow formula

Process formulas reference [Object].Field or myVariable_current.Field; flow formulas need {!$Record.Field}. A cross-object reference in a process formula cannot be migrated at all - it needs a Get Records element and a new formula.

Migrating with the process left active "until we are sure"

Two automations writing one field in one save, ordered by nothing. If confidence is the problem, the answer is a sandbox and a scratch org, not a double write.

Reading the process file into the session to plan the migration

Tens of thousands of tokens for information plan prints in twenty lines.

Verification

# The process file is a process, and this is what it does
node "$CLAUDE_PLUGIN_ROOT/scripts/vf-process-to-flow.js" plan <process file>

# The generated flow: XML shape, api version, formatting, static analysis
node "$CLAUDE_PLUGIN_ROOT/scripts/checks/vf-check.mjs" local --files <flow file>
node "$CLAUDE_PLUGIN_ROOT/scripts/checks/vf-check.mjs" analyzer --files <flow file>

# The org accepts it, without deploying it
sf project deploy validate --source-dir <flow file> --target-org <alias>

# After deploy: the flow is the active version and the process is not
sf data query --use-tooling-api --target-org <alias> \
  --query "SELECT ApiName, ProcessType, Status, VersionNumber FROM FlowDefinitionView WHERE ApiName IN ('Case_triage','Case_New_and_mine_Before')"

# The behaviour, on a real record
sf data create record --sobject Case --values "Status=New Origin=Web" --target-org <alias>
sf data query --query "SELECT Id, Priority, Subject FROM Case ORDER BY CreatedDate DESC LIMIT 1" --target-org <alias>

# Which automation actually ran
sf apex get log --number 1 --target-org <alias> | grep -E "FLOW_|CODE_UNIT_STARTED"

sf-post-deploy-verification owns the probe-and-rollback decision; sf-debugging-logs owns the FLOW_* markers and the Workflow log category that records processes and flows.

References

  • references/process-metadata-anatomy.md - a process file element by element, the reference and operator mapping tables, the converter's contract and exit codes
  • references/migrate-to-flow-tool.md - the Setup tool's supported and unsupported lists, partial migration, scheduled actions, the manual conversion methods

Sibling skills: sf-flow-automation (the flow you are building, plus workflow rule migration), sf-apex-development (order of execution, invocable Apex), sf-technical-debt-audit (finding the processes still running), sf-minimal-change (how small the change should be), sf-project-structure (flows/ and the metadata token bill), sf-deployment-strategies (flow activation on deploy), sf-post-deploy-verification (proving the cutover worked).

Sources: Metadata API Developer Guide, Flow (FlowProcessType, FlowStart, FlowRecordFilter, FlowRecordFilterOperator, FlowScheduledPath); "Automate Your Business Processes" - Process Builder, Execute Actions for Multiple Criteria, Reevaluate Records in the Process Builder, Migrate to Flow Tool Considerations, Move Processes and Workflows to Flow Builder with the Migrate to Flow Tool; Salesforce Help, end of support for Workflow Rules and Process Builder. API version 67.0.

Download now (ZIP)

Does it work?

Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.

No reviews yet

People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.

  • It worked
  • Partly
  • It didn't
What did you use it for? e.g. Reviewing pull requests in a Rails app

Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.

Your trail

Files you open will collect here, so you can find them again.

Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.

Now do this for your own.

Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.