# Sf Flow

> Creates and validates Salesforce flows with 110-point scoring and Winter '26 best practices using Salesforce MCP server. Use when building record-triggered flows, screen flows, autolaunched flows, scheduled flows, or reviewing existing flow performance. Do NOT use for Apex classes and triggers (use sf-apex), creating the objects and fields a flow references (use sf-metadata), or diagnosing a flow failure at runtime from debug logs (use sf- debug). Usage: /sf-flow [create|update|validate] {FlowName} ...

- Skill: `kugamon/sf-flow` (Agent Skill, multi-file: 64 files)
- Install (CLI): `npx skillmds@latest add kugamon/sf-flow`
- Raw SKILL.md: https://api.skillmd.com/api/skills/kugamon/sf-flow/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: AI & ML
- Author: kugamon (https://skillmd.com/u/kugamon)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/kugamon/sf-flow

---


# 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 Won` until approved) you ALSO need a **validation rule** keyed off either a custom "approved" flag (set by a final-approval field update / background step) or `PRIORVALUE(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` (NOT `recordEditabilityType`); the "Submit for Approval" standard button is `Submit` inside `excludeButtons`; OpportunityStage values are governed by `won`/`closed`/`forecastCategory`, not just `label`.
- **Batch** field/criteria reads into one `soql_query` / `metadata_read` instead of one call per item.
- Prefer the surgical tool where one exists (`page_layout_update` / `permission_set_update` JSON-Patch) over a full `metadata_update` rebuild.

---

## 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 `InvalidDraft` states that only surface at runtime. A skill-scoped `PreToolUse` hook (`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:

```bash
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:

1. Did I write the Flow metadata to a file?
2. Did I run `validate_flow_cli.py` on that file?
3. Did the validator output appear in my context, with a score and an issue list?
4. 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:

```bash
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:

```bash
# $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

```bash
python3 "${CLAUDE_PLUGIN_ROOT}/skills/sf-flow/scripts/validate_flow_cli.py" "<file_path>"
```

### Flow API name (fetch from org)

1. Fetch the Flow XML:

```
metadata_read(
  type="Flow",
  fullNames=["<FlowApiName>"],
  sf_user="<sf_user>"
)
```

2. Write the XML content to a temp file:

```
Write /tmp/validate_<FlowApiName>.flow-meta.xml  ← the flow XML
```

3. Validate:

```bash
python3 "${CLAUDE_PLUGIN_ROOT}/skills/sf-flow/scripts/validate_flow_cli.py" "/tmp/validate_<FlowApiName>.flow-meta.xml"
```

4. 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

1. Fetch all flow names:

```
metadata_list(type="Flow", sf_user="<sf_user>")
```

2. 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.

3. Validate each flow (write → validate → delete).
4. Show the summary table sorted by score ascending.
5. Highlight any below 88/110 (80%) as requiring attention.

---

## 📋 Quick Reference: Validation and Deployment

**Flow Creation & Deployment Workflow:**

```text
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

1. **Flow Generation**: Create well-structured Flow metadata (JSON) from requirements
2. **Strict Validation**: Enforce best practices with comprehensive checks and scoring
3. **the Salesforce MCP server Integration**: Deploy via metadata_create, retrieve via metadata_read/metadata_list
4. **Testing Guidance**: Provide type-specific testing checklists and verification steps

---

## ⚠️ CRITICAL: Salesforce MCP server Setup

**BEFORE using any Salesforce MCP tools:**

```python
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.

```text
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:

1. Call `org_init()` (always required)
2. Use `sobject_describe` to verify the target object/fields exist
3. Generate the flow metadata as JSON
4. Run guardrail checks (anti-patterns only — skip full 110-point scoring)
5. Deploy via `metadata_create`
6. 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**:

1. **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.
2. Use `sobject_describe` to verify object/field existence before referencing
3. Use `metadata_list` to check existing flows: `metadata_list(type="Flow")`
4. Offer reusable subflows: Sub_LogError, Sub_SendEmailAlert, Sub_ValidateRecord, Sub_UpdateRelatedRecords, Sub_QueryRecordsWithRetry → See `references/subflow-library.md`
5. If complex automation: Reference `references/governance-checklist.md`
6. 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):

1. Resolve paths relative to the skill root under `assets/[template]`
2. 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.md` and `references/orchestration-guide.md`

### Phase 3: Flow Generation & Deployment (via MCP)

> **Two deployment formats — know which to use:**
>
> | Path                                     | Format          | When                              |
> | ---------------------------------------- | --------------- | --------------------------------- |
> | `metadata_create` / `metadata_update`    | **JSON object** | Deploying via Salesforce MCP server |
> | Writing `.flow-meta.xml` to `force-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 in
> `assets/` are the correct reference when writing local `.flow-meta.xml` files.

**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 `bulkSupport` property (removed API 60.0+)
- Auto-Layout: all `locationX`/`locationY` = 0
- Fault paths on all DML operations

#### JSON Format Reference

> **Read `assets/json-deployment-reference.md` for 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):

1. **Format**: `metadata_create` requires a JSON object, NOT XML. The XML templates
   in `assets/` show structure; translate using the reference above.
2. **Property placement**: `triggerType`, `recordTriggerType`, `object`, `schedule`,
   `filters`/`filterFormula`/`filterLogic` belong ONLY inside `start`, never at top level.
3. **Value wrappers**: `{"stringValue": "text"}`, `{"booleanValue": true}`,
   `{"numberValue": 100}`, `{"elementReference": "var_Name"}`.
4. **Merge fields**: `stringValue` supports `{!$Record.Name}` syntax — no need for
   formula variables for simple string interpolation.
5. **Entry conditions**: Use `filterFormula` for compound/negated conditions
   (`AND()`, `OR()`, `NOT()`). Use `filters` array for simple field comparisons.
6. **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.

```python
# 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**:

```python
# 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.

```python
# 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 org
- `python 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**:

- `storeOutputAutomatically` detection (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):

```text
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**:

1. **Initialize connection** (once per session):

```python
org_init()
```

1. **Deploy Flow metadata** (JSON, not XML):

> **Validation is your job, not the hook's.** A `PreToolUse` hook (`scripts/pre-mcp-validate.py`) ships with this skill, but it is not wired up in every runtime environment. **Always run `validate_flow_cli.py` manually** on the metadata file before calling `metadata_create`, `metadata_update`, or `tooling_api_dml` on 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.

```python
# 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"
)
```

1. **Retrieve existing flows** (to review or modify):

```python
metadata_read(
    type="Flow",
    fullNames=["Auto_Lead_Assignment"],
    sf_user="your-salesforce-username"
)
```

1. **List all flows** (for reference):

```python
metadata_list(
    type="Flow",
    sf_user="your-salesforce-username"
)
```

1. **Query Flow metadata** (Tooling API):

```python
tooling_api_q

…(truncated)
