Salesforce Flow Development and Review
Expert Salesforce Flow Builder with deep knowledge of best practices, bulkification, and Winter '26 (API 65.0) metadata. Create production-ready, performant, secure, and maintainable flows using Salesforce MCP server for deployment.
Dispatch
Parse $ARGUMENTS to determine the action:
| First argument or intent | Workflow |
|---|---|
create, new flow request |
Create Flow |
update, modify existing flow |
Update Flow |
validate, review, score |
Validate Flow |
| (no argument or unclear) | Ask the user (see below) |
When the operation is missing or unclear, you MUST use AskUserQuestion before proceeding:
AskUserQuestion(question="What would you like to do?\n\n1. **Create** — generate a new Flow\n2. **Update** — fetch, modify, validate, and redeploy\n3. **Validate** — score an existing Flow")
Do NOT guess the operation or default to one. Wait for the user's answer.
Approval Processes: Choose the Engine First
When a request is to build an approval (e.g. "create an approval process", "require approval before X", "deal/discount approval", "gate a stage until approved"), do NOT start building until the engine is decided:
| Engine | Build with | Use when |
|---|---|---|
| Flow Approval Orchestration (recommended) | this skill (processType Orchestrator, record-triggered) + the Setup approval wizard for the approval step |
Default. Salesforce's active investment; native record-change auto-trigger; Approval Trace audit log; recall/reassign; Apex-extensible; free (no orchestration credits). |
| Legacy (classic) Approval Process | sf-metadata (ApprovalProcess metadata type) |
Simple single-step manager approvals; need built-in delegate approver; org already standardized on classic. |
If the user has not explicitly named the engine, ASK (one question) and recommend Flow Approval Orchestration. Do not default silently.
AskUserQuestion(question="Build this as a **Flow Approval Orchestration** (recommended — record-change auto-trigger, audit trace, Salesforce's strategic direction) or a **legacy Approval Process** (simpler, built-in delegate approver)?")
Set expectations up front (true for BOTH engines):
- An approval process cannot prevent a field transition by itself. To gate (e.g. block
Closed Wonuntil approved) you ALSO need a validation rule keyed off either a custom "approved" flag (set by a final-approval field update / background step) orPRIORVALUE(StageName). - Auto-trigger on record change is native to Flow record-triggered orchestrations; classic needs a separate record-triggered auto-submit flow.
- The orchestration's approval step subtype does not reliably round-trip through the Metadata API — assemble that step in the Setup approval wizard / Flow Builder. Build the supporting approver screen flow and background field-update flow with this skill, then wire them in the wizard.
Minimize metadata round-trips
- Read before update for any element the API replaces wholesale (
Layout,ApprovalProcess,StandardValueSet,Flow): fetch current → change the one field → send the complete payload. A partial payload silently drops siblings. - Use exact metadata element names — do not infer them from the Setup UI label. Known mismatches:
recordEditability(NOTrecordEditabilityType); the "Submit for Approval" standard button isSubmitinsideexcludeButtons; OpportunityStage values are governed bywon/closed/forecastCategory, not justlabel. - Batch field/criteria reads into one
soql_query/metadata_readinstead of one call per item. - Prefer the surgical tool where one exists (
page_layout_update/permission_set_updateJSON-Patch) over a fullmetadata_updaterebuild.
Action Workflow: Create Flow
Create a new Flow following Winter '26 best practices.
Step 1. Gather requirements
Use AskUserQuestion to collect:
- Flow type: Record-Triggered, Screen, Autolaunched, Scheduled, or Platform Event-Triggered
- Trigger object (if record-triggered): which Salesforce object
- Trigger event (if record-triggered): before save, after save, or both
- Primary purpose: one sentence description
- Special requirements: subflows, invocable actions, external callouts, etc.
Step 2. Check for existing flow
Before generating, confirm the flow doesn't already exist:
metadata_list(
type="Flow",
sf_user="<sf_user>"
)
If it exists, suggest running with update <FlowApiName> instead.
Step 3. Generate
Create the flow XML following the sf-flow skill guidelines (see Workflow Design section below):
- Proper API naming conventions (snake_case with descriptive prefix)
- Fault paths on all DML and callout elements
- Bulkification patterns (no DML or SOQL in loops)
- Description and labels on all elements
runInMode="SystemModeWithoutSharing"only where justified
Step 4. Validate before deploying — REQUIRED, MANUAL
This step is not optional and is not automated. Skipping it has shipped Flows with broken email actions, missing fault paths, and
InvalidDraftstates that only surface at runtime. A skill-scopedPreToolUsehook (scripts/pre-mcp-validate.py) ships with this skill, but it is not wired up in every runtime environment — until you confirm the hook is registered for your host, treat the manual step below as the contract.
Write the generated metadata to a temp file (/tmp/<FlowApiName>.flow-meta.xml for XML, /tmp/<FlowApiName>.flow.json for JSON), then run:
python3 "${CLAUDE_PLUGIN_ROOT}/skills/sf-flow/scripts/validate_flow_cli.py" "/tmp/<FlowApiName>.flow-meta.xml"
Fix any CRITICAL or HIGH issues before deploying — including missing faultConnector on actionCalls, recordCreates, recordUpdates, recordDeletes, recordLookups, apexPluginCalls, and waits with callouts. A score below 80% (88/110) is a hard stop unless you explicitly state in your response why the deployment is going ahead anyway.
Self-check before every metadata_create / metadata_update / tooling_api_dml call on a Flow. Answer these four questions out loud (in your reasoning) before invoking the tool:
- Did I write the Flow metadata to a file?
- Did I run
validate_flow_cli.pyon that file? - Did the validator output appear in my context, with a score and an issue list?
- Are all CRITICAL/HIGH issues resolved?
If you cannot answer "yes" to all four, do not call the deployment tool. Stop, run the validator, and resume.
Default fault-routing rule for every Flow. Every element that can fault at runtime needs a faultConnector: every actionCalls (email, callout, invocable Apex), every recordCreates / recordUpdates / recordDeletes / recordLookups, every apexPluginCalls, and every waits involving a callout. Routing the fault to a no-op terminal element is acceptable; routing it to the success path is not (it hides failures).
Step 5. Deploy
metadata_create(
type="Flow",
metadata=[{"fullName": "<FlowApiName>", "label": "<Flow Label>", "apiVersion": 65, "processType": "<ProcessType>", "status": "Draft", ...}]
)
Step 6. Report
Show the final validation score and deployment status.
Action Workflow: Update Flow
Fetch, modify, validate, and redeploy an existing Salesforce Flow.
Parsing the request
The argument should be a flow API name: update Auto_Lead_Assignment do X
If no flow name is given, ask the user which flow to update and what changes are needed.
Step 1. Fetch the current implementation
metadata_read(
type="Flow",
fullNames=["<FlowApiName>"],
sf_user="<sf_user>"
)
If the flow is not found, suggest running with create instead.
Step 2. Read and understand
Review the existing flow XML before making any changes. Understand:
- Flow type and trigger configuration
- Existing element names and labels
- What the requested change affects
Step 3. Apply changes
Modify the flow following sf-flow skill guidelines. Preserve:
- Existing element names and API references (other flows/components may reference them)
- Existing fault paths and error handling
- Description and label conventions already in use
Step 4. Validate before deploying — REQUIRED, MANUAL
The same four-question self-check from the Create workflow applies here. The hook is not guaranteed to be wired up; the manual validator run is the contract. Write the updated metadata to a temp file and validate:
python3 "${CLAUDE_PLUGIN_ROOT}/skills/sf-flow/scripts/validate_flow_cli.py" "/tmp/<FlowApiName>.flow-meta.xml"
Fix any CRITICAL or HIGH issues before deploying. Score below 80% (88/110) is a hard stop unless you can explain why the deployment is going ahead anyway.
Step 5. Deploy
metadata_update(
type="Flow",
metadata=[{"fullName": "<FlowApiName>", "label": "<Flow Label>", "apiVersion": 65, "processType": "<ProcessType>", "status": "Draft", ...}]
)
Step 6. Report
Summarise the changes made and show the final validation score.
Action Workflow: Validate Flow
Validate one or more Flows using the 110-point static analysis pipeline and return a scored report.
Parsing the request
Input after validate |
Interpretation |
|---|---|
Auto_Lead_Assignment |
Flow API name — fetch XML from org, validate |
force-app/.../Auto_Lead_Assignment.flow-meta.xml (ends .flow-meta.xml or .xml) |
Local file — validate directly |
Auto_Lead_Assignment,Screen_Case_Intake |
Comma-separated list — bulk fetch, validate each |
All |
All Flow records in the org |
| (no argument) | Ask the user what to validate |
Validation script
The validation script is at ${CLAUDE_PLUGIN_ROOT}/skills/sf-flow/scripts/validate_flow_cli.py. Locate it with:
# $CLAUDE_PLUGIN_ROOT is set by Claude Code. Other hosts: see references/execution-modes.md.
# If not set, find the script:
find ~/.claude/plugins -name "validate_flow_cli.py" 2>/dev/null | grep sf-flow | head -1
Local file
python3 "${CLAUDE_PLUGIN_ROOT}/skills/sf-flow/scripts/validate_flow_cli.py" "<file_path>"
Flow API name (fetch from org)
- Fetch the Flow XML:
metadata_read(
type="Flow",
fullNames=["<FlowApiName>"],
sf_user="<sf_user>"
)
- Write the XML content to a temp file:
Write /tmp/validate_<FlowApiName>.flow-meta.xml ← the flow XML
- Validate:
python3 "${CLAUDE_PLUGIN_ROOT}/skills/sf-flow/scripts/validate_flow_cli.py" "/tmp/validate_<FlowApiName>.flow-meta.xml"
- Delete the temp file after validation.
Comma-separated list
Fetch all flow XML bodies in a single call:
metadata_read(
type="Flow",
fullNames=["Flow1", "Flow2", "Flow3"],
sf_user="<sf_user>"
)
Fallback: If the bulk read fails (timeout or size error), fall back to individual metadata_read calls per flow.
Validate each flow body (write → validate → delete). After all flows are validated, show a summary table sorted by score ascending (worst first):
| Flow | Score | % | Status |
|---|---|---|---|
| Before_Opportunity_Validate | 72/110 | 65% | Below threshold |
| Auto_Lead_Assignment | 98/110 | 89% | Pass |
All
- Fetch all flow names:
metadata_list(type="Flow", sf_user="<sf_user>")
- Fetch flow XML in batches of 20 (large flows can make bigger batches fail):
metadata_read(
type="Flow",
fullNames=["Flow1", ..., "Flow20"],
sf_user="<sf_user>"
)
Backoff strategy: If a batch of 20 fails (timeout or response size error), retry with 10, then 5, then fall back to individual reads for that batch.
- Validate each flow (write → validate → delete).
- Show the summary table sorted by score ascending.
- Highlight any below 88/110 (80%) as requiring attention.
📋 Quick Reference: Validation and Deployment
Flow Creation & Deployment Workflow:
1. Call org_init (REQUIRED - one per session)
2. Generate Flow metadata (JSON object — NOT XML)
3. Deploy via metadata_create tool (Salesforce MCP server)
4. Retrieve existing flows via metadata_read or metadata_list (Salesforce MCP server)
5. Query Flow metadata via tooling_api_query for FlowDefinition
6. Describe objects/fields via sobject_describe before flow creation
(org_init is a convention — see the Tool-name mapping in references/execution-modes.md.)
Scoring: 110 points across 6 categories. Minimum 88 (80%) for deployment. Trivial flows (single-step automations, test/throwaway flows) are exempt from the minimum threshold — score them for informational purposes but do not block deployment. Guardrail anti-pattern checks (DML in loops, missing fault paths) still apply regardless of complexity.
Execution modes
This skill supports four execution modes — see
references/execution-modes.md for detection logic and full details,
and references/mcp-pagination.md for handling large MCP responses.
All Flow operations go through MCP tools regardless of mode. The mode determines whether local tooling (filesystem, code execution) is available for post-processing and how large query results are retrieved.
Core Responsibilities
- Flow Generation: Create well-structured Flow metadata (JSON) from requirements
- Strict Validation: Enforce best practices with comprehensive checks and scoring
- the Salesforce MCP server Integration: Deploy via metadata_create, retrieve via metadata_read/metadata_list
- Testing Guidance: Provide type-specific testing checklists and verification steps
⚠️ CRITICAL: Salesforce MCP server Setup
BEFORE using any Salesforce MCP tools:
org_init()
Call with no parameters — uses the default org. If a default is configured, confirm with the user before proceeding. If no default is configured, ask for the Salesforce user/alias.
This initializes your Salesforce org connection. It must be called once per session before using any of these Salesforce MCP tools:
metadata_create(deploy flows)metadata_read(retrieve flows)metadata_list(list existing flows)tooling_api_query(query FlowDefinition)sobject_describe(verify objects/fields)soql_query(query org data)
⚠️ CRITICAL: Orchestration Order
sf-metadata → sf-flow → sf-data (you are here: sf-flow with the Salesforce MCP server)
⚠️ Flow references custom object/fields? Create with sf-metadata FIRST. Deploy objects BEFORE flows.
1. sf-metadata → Create objects/fields (local)
2. sf-flow ◀── YOU ARE HERE (create flow, deploy via MCP)
3. sf-data → Create test data (remote - objects must exist!)
See references/orchestration.md for extended orchestration patterns including Agentforce.
🔑 Key Insights
| Insight | Details |
|---|---|
| Before vs After Save | Before-Save: same-record updates (no DML), validation. After-Save: related records, emails, callouts |
| Test with 251 | Batch boundary at 200. Test 251+ records for governor limits, N+1 patterns, bulk safety |
| $Record context | Single-record, NOT a collection. Platform handles batching. Never loop over $Record |
| $Record traversal | $Record supports relationship traversal: {!$Record.Contact__r.FirstName}, {!$Record.Account__r.Name}. Do NOT use Get Records for data already available through $Record lookups — this wastes a SOQL query |
| Transform vs Loop | Transform: data mapping/shaping (30-50% faster). Loop: per-record decisions, counters, varying logic. See references/transform-vs-loop-guide.md |
Fast Path (Simple Requests)
For simple, self-contained flows (single record update, basic field mapping, straightforward screen flow), bypass the detailed requirements/design elaboration and full scoring while still performing initialization and mandatory guardrails, then generate + deploy:
- Call
org_init()(always required) - Use
sobject_describeto verify the target object/fields exist - Generate the flow metadata as JSON
- Run guardrail checks (anti-patterns only — skip full 110-point scoring)
- Deploy via
metadata_create - Verify deployment
Use the fast path when: the request is explicit, the flow is a single straightforward automation, and there are no ambiguous requirements.
Use the full 5-phase workflow when: the flow involves multiple decision branches, screen flows with complex logic, subflow orchestration, or underspecified requirements.
Workflow Design (5-Phase Pattern)
Phase 1: Requirements Gathering
Before building, evaluate alternatives: See references/flow-best-practices.md Section 1 "When NOT to Use Flow" - sometimes a Formula Field, Validation Rule, or Roll-Up Summary Field is the better choice. The shared cross-skill routing tree (formula/rollup vs flow vs Apex, before-save vs after-save, when not to automate at all) is ../../shared/standards/automation-decision-tree.md — consult it when the request might belong on the Apex side of the fence.
If the request is underspecified, ask concise follow-up questions to gather:
- Flow type (Screen, Record-Triggered After/Before Save/Delete, Platform Event, Autolaunched, Scheduled)
- Primary purpose (one sentence)
- Trigger object/conditions (if record-triggered)
Pre-Development Planning: For complex flows, document requirements and sketch logic before building. See references/flow-best-practices.md Section 2 "Pre-Development Planning" for templates and recommended tools.
Then:
- Initialize: Call
org_init()with no parameters. If a default org is configured, confirm with the user. If no default, ask for the Salesforce user/alias before proceeding. - Use
sobject_describeto verify object/field existence before referencing - Use
metadata_listto check existing flows:metadata_list(type="Flow") - Offer reusable subflows: Sub_LogError, Sub_SendEmailAlert, Sub_ValidateRecord, Sub_UpdateRelatedRecords, Sub_QueryRecordsWithRetry → See
references/subflow-library.md - If complex automation: Reference
references/governance-checklist.md - Keep an internal checklist: Gather requirements, select template, generate flow metadata (JSON), validate, deploy, test
Phase 2: Flow Design & Template Selection
Select template:
| Flow Type | Template File |
|---|---|
| Screen | screen-flow-template.xml |
| Record-Triggered | record-triggered-*.xml |
| Platform Event | platform-event-flow-template.xml |
| Autolaunched | autolaunched-flow-template.xml |
| Scheduled | scheduled-flow-template.xml |
| Wait Elements | wait-template.xml |
Element Pattern Templates (assets/elements/):
| Element | Template | Purpose |
|---|---|---|
| Loop | loop-pattern.xml |
Complete loop with nextValueConnector/noMoreValuesConnector |
| Get Records | get-records-pattern.xml |
All recordLookups options (filters, sort, limit) |
| Delete Records | record-delete-pattern.xml |
Filter-based and reference-based delete patterns |
JSON Deployment Reference (assets/json-deployment-reference.md):
Covers XML-to-JSON translation, property placement rules, start patterns for all flow types, entry conditions (filterFormula vs filters), value reference patterns, and element JSON examples. For metadata_create deployments, this reference alone is usually sufficient — the XML templates are optional structural references for complex or unfamiliar flow types.
Template Path Resolution (try in order):
- Resolve paths relative to the skill root under
assets/[template] - For element snippets, resolve paths under
assets/elements/[template]
When to read XML templates: Only when dealing with complex or unfamiliar element patterns (e.g., wait elements, advanced screen flows). For standard record-triggered, autolaunched, and scheduled flows, the JSON deployment reference has all the patterns needed.
Example: Read: assets/record-triggered-after-save.xml
Naming Convention (Recommended Prefixes):
| Flow Type | Prefix | Example |
|---|---|---|
| Record-Triggered (After) | Auto_ |
Auto_Lead_Assignment, Auto_Account_Update |
| Record-Triggered (Before) | Before_ |
Before_Lead_Validate, Before_Contact_Default |
| Screen Flow | Screen_ |
Screen_New_Customer, Screen_Case_Intake |
| Scheduled | Sched_ |
Sched_Daily_Cleanup, Sched_Weekly_Report |
| Platform Event | Event_ |
Event_Order_Completed |
| Autolaunched | Sub_ or Util_ |
Sub_Send_Email, Util_Validate_Address |
Format: [Prefix]_Object_Action using PascalCase (e.g., Auto_Lead_Priority_Assignment)
Screen Flow Button Config (CRITICAL):
| Screen | allowBack | allowFinish | Result |
|---|---|---|---|
| First | false | true | "Next" only |
| Middle | true | true | "Previous" + "Next" |
| Last | true | true | "Finish" |
Rule: allowFinish="true" required on all screens. Connector present → "Next", absent → "Finish".
Orchestration: For complex flows (multiple objects/steps), suggest Parent-Child or Sequential pattern.
- CRITICAL: Record-triggered flows CANNOT call subflows via metadata deployment. Use inline orchestration instead. See
references/xml-gotchas.mdandreferences/orchestration-guide.md
Phase 3: Flow Generation & Deployment (via MCP)
Two deployment formats — know which to use:
Path Format When metadata_create/metadata_updateJSON object Deploying via Salesforce MCP server Writing .flow-meta.xmltoforce-app/XML Source-controlled project files CRITICAL: Do NOT pass XML strings to
metadata_create. It requires a structured JSON object — use the format reference and examples below. The XML templates inassets/are the correct reference when writing local.flow-meta.xmlfiles.
Generate flow metadata: Construct the complete Flow metadata as a JSON object with:
- API Version: 65.0
- Proper alphabetical property ordering
- All required metadata fields (
label,processType,status, etc.)
CRITICAL Requirements:
- Alphabetical property ordering at root level
- NO
bulkSupportproperty (removed API 60.0+) - Auto-Layout: all
locationX/locationY= 0 - Fault paths on all DML operations
JSON Format Reference
Read
assets/json-deployment-reference.mdfor the complete reference — it covers XML-to-JSON translation, start patterns for all flow types, entry conditions, value references, and element JSON examples.
Essential rules (always apply):
- Format:
metadata_createrequires a JSON object, NOT XML. The XML templates inassets/show structure; translate using the reference above. - Property placement:
triggerType,recordTriggerType,object,schedule,filters/filterFormula/filterLogicbelong ONLY insidestart, never at top level. - Value wrappers:
{"stringValue": "text"},{"booleanValue": true},{"numberValue": 100},{"elementReference": "var_Name"}. - Merge fields:
stringValuesupports{!$Record.Name}syntax — no need for formula variables for simple string interpolation. - Entry conditions: Use
filterFormulafor compound/negated conditions (AND(),OR(),NOT()). Usefiltersarray for simple field comparisons. - Shell template: Start from the Flow Shell Template below (Lesson 9) for the complete JSON boilerplate with all element arrays.
Pre-Deployment: Check Prerequisites (REQUIRED for flows referencing custom fields/objects):
Before deploying a flow, verify that all referenced custom fields and objects exist
in the target org. Flows referencing missing fields will deploy but become
InvalidDraft and cannot be activated.
# Check if custom field exists before deploying flow that references it
sobject_describe(sObject="Lead")
# Verify TEST_Priority__c (or any custom field) appears in the field list
# If missing: create the field FIRST via sobject_field_create, then deploy the flow
Deploy via MCP:
# Initialize connection (ONCE per session)
org_init(sf_user="your-username")
# Create/deploy Flow — pass a JSON object, NOT XML
metadata_create(
type="Flow",
metadata=[{
"fullName": "Auto_Lead_Assignment",
"label": "Auto Lead Assignment",
"apiVersion": 65,
"description": "Assigns new leads to the appropriate queue based on region",
"environments": ["Default"],
"processMetadataValues": [
{"name": "BuilderType", "value": {"stringValue": "LightningFlowBuilder"}},
{"name": "CanvasMode", "value": {"stringValue": "AUTO_LAYOUT_CANVAS"}}
],
"processType": "AutoLaunchedFlow",
"start": {
"locationX": 0, "locationY": 0,
"object": "Lead",
"recordTriggerType": "Create",
"triggerType": "RecordAfterSave",
"connector": {"targetReference": "Check_Region"}
},
"decisions": [...],
"recordUpdates": [...],
"status": "Draft"
}],
sf_user="your-username"
)
Post-Deployment: Verify Flow Status (REQUIRED after every metadata_create for Flow):
After deploying a flow, immediately query its status via the Tooling API to
detect InvalidDraft. This catches issues the Metadata API accepts silently.
# Check flow status after deployment
tooling_api_query(
sObject="Flow",
fields=["Id", "Definition.DeveloperName", "VersionNumber", "Status"],
whereClause="Definition.DeveloperName = 'Auto_Lead_Assignment'"
)
# Expected: Status = "Draft"
# If Status = "InvalidDraft":
# 1. Check for missing triggerType (scheduled flows need triggerType=Scheduled)
# 2. Check for missing custom field references (sobject_describe to verify)
# 3. Fix the issue and redeploy via metadata_update
Common InvalidDraft Causes and Fixes:
| Cause | Symptom | Fix |
|---|---|---|
Missing triggerType in start |
Scheduled flow with schedule but no triggerType: Scheduled |
Add triggerType: "Scheduled" to start element |
| Missing custom field | Flow references Custom_Field__c that doesn't exist |
Create field via sobject_field_create first, then redeploy |
Deprecated bulkSupport |
API 60.0+ flow includes bulkSupport |
Remove the bulkSupport property |
Missing recordTriggerType |
Record-triggered flow without recordTriggerType |
Add recordTriggerType: "Create" (or Update/CreateAndUpdate) |
Missing locationX/locationY on start |
Required field is missing: locationX on create |
Always include "locationX": 0, "locationY": 0 on the start element, even for auto-layout flows |
For Review — validate an existing flow from the org or a local file before modifying:
python scripts/validate_flow_cli.py <FlowApiName>— fetch and validate a single flow from the orgpython scripts/validate_flow_cli.py All— full org audit sorted by score
Validation (STRICT MODE):
- BLOCK: Invalid structure, missing required fields (apiVersion/label/processType/status), API <65.0, broken refs, DML in loops
- WARN: Property ordering, deprecated properties, non-zero coords, missing fault paths, unused vars, naming violations
New v2.0.0 Validations:
storeOutputAutomaticallydetection (data leak prevention)- Same-object query anti-pattern (recommends $Record usage)
- Complex formula in loops warning
- Missing filters on Get Records
- Null check after Get Records recommendation
- Variable naming prefix validation (var*, col*, rec*, inp*, out_)
Validation Report Format (6-Category Scoring 0-110):
Score: 92/110 ⭐⭐⭐⭐ Very Good
├─ Design & Naming: 18/20 (90%)
├─ Logic & Structure: 20/20 (100%)
├─ Architecture: 12/15 (80%)
├─ Performance & Bulk Safety: 20/20 (100%)
├─ Error Handling: 15/20 (75%)
└─ Security: 15/15 (100%)
Strict Mode: If ANY errors/warnings → Block with options: (1) Apply auto-fixes, (2) Show manual fixes, (3) Generate corrected version. DO NOT PROCEED until 100% clean.
⛔ GENERATION GUARDRAILS (MANDATORY)
BEFORE generating ANY Flow metadata, VERIFY no anti-patterns are introduced.
If ANY of these patterns would be generated, STOP and ask the user:
"I noticed [pattern]. This will cause [problem]. Should I: A) Refactor to use [correct pattern] B) Proceed anyway (not recommended)"
| Anti-Pattern | Impact | Correct Pattern |
|---|---|---|
| After-Save updating same object without entry conditions | Infinite loop (critical) | MUST add entry conditions: "Only when [field] is changed" |
| Get Records inside Loop | Governor limit failure (100 SOQL) | Query BEFORE loop, use collection variable |
| Create/Update/Delete Records inside Loop | Governor limit failure (150 DML) | Collect in loop → single DML after loop |
| Apex Action inside Loop | Callout limits | Pass collection to single Apex invocation |
Fallible element in RecordAfterSave flow without faultConnector |
Blocks the originating save (CANNOT_EXECUTE_FLOW_TRIGGER). Applies to recordCreates, recordUpdates, recordDeletes, recordLookups, and actionCalls (incl. emailSimple, callouts, platform events, custom notifications) |
Add faultConnector to every fallible element. If save-gating is intentional, use RecordBeforeSave and document in description |
| Get Records without null check | NullPointerException | Add Decision: "Records Found?" after query |
storeOutputAutomatically=true in system-mode flow with sensitive data |
Security risk (retrieves ALL fields) | Use explicit field selection only when flow runs in system mode AND queries objects with sensitive fields (SSN, credit card, etc.) |
| Query same object as trigger in Record-Triggered | Wasted SOQL | Use {!$Record.FieldName} directly |
Get Records for data available via $Record lookup |
Wasted SOQL | Use {!$Record.Lookup__r.Field} — traversal works up to 5 levels |
| Hardcoded Salesforce ID | Deployment failure across orgs | Use input variable or Custom Label |
| Get Records without filters | Too many records returned | Always include WHERE conditions |
DO NOT generate anti-patterns even if explicitly requested. Ask user to confirm the exception with documented justification.
Phase 4: Deployment & Integration (via Salesforce MCP)
the Salesforce MCP server Deployment Pattern:
- Initialize connection (once per session):
org_init()
- Deploy Flow metadata (JSON, not XML):
Validation is your job, not the hook's. A
PreToolUsehook (scripts/pre-mcp-validate.py) ships with this skill, but it is not wired up in every runtime environment. Always runvalidate_flow_cli.pymanually on the metadata file before callingmetadata_create,metadata_update, ortooling_api_dmlon a Flow. Block deployment for CRITICAL/HIGH issues; treat score below 80% (88/110) as a hard stop unless you explicitly state why you're proceeding anyway. See the four-question self-check in the Create workflow above.
# Pass a structured JSON object — see org_init instructions for format examples
metadata_create(
type="Flow",
metadata=[{
"fullName": "Auto_Lead_Assignment",
"label": "Auto Lead Assignment",
"apiVersion": 65,
"processType": "AutoLaunchedFlow",
"status": "Draft",
# ... full flow structure as JSON properties
}],
sf_user="your-salesforce-username"
)
- Retrieve existing flows (to review or modify):
metadata_read(
type="Flow",
fullNames=["Auto_Lead_Assignment"],
sf_user="your-salesforce-username"
)
- List all flows (for reference):
metadata_list(
type="Flow",
sf_user="your-salesforce-username"
)
- Query Flow metadata (Tooling API):
tooling_api_q
…(truncated)