Azure (Microsoft) logo

Skill

workflow-json-generation-rules

generate workflow.json files for Logic Apps

Covers Azure Configuration Automation Workflow Automation

Description

Rules for generating workflow.json files for Logic Apps Standard. Covers connector selection, splitOn preference, file trigger semantics, runAfter structure, and mandatory reference lookup before writing.

SKILL.md

Skill: Workflow JSON Generation Rules

Purpose: Authoritative rules for generating workflow.json files. Follow exactly.


1. Mandatory Reference Lookup

BEFORE writing ANY workflow.json:

  1. Read the skill source-to-logic-apps-mapping to get the Logic Apps equivalent connector, service provider ID, and operation names for each source component.
  2. Use those operation names to call migration_searchReferenceWorkflows and migration_readReferenceWorkflow to get exact operationId and serviceProviderConfiguration for each trigger/action.
  3. If the first search returns no relevant results, RETRY 2-4 more times with different word combinations.
  4. Also call migration_readReferenceDoc with action="search" then action="read" to verify connector capabilities.
  5. Do NOT invent operationId values, serviceProviderConfiguration structures, or connection formats — ALWAYS copy from references.

2. Workflow Definition Structure

Each workflow.json must contain a definition key with:

  • $schema — MUST be exactly "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#"
  • contentVersion — use "1.0.0.0"
  • triggers — at least one trigger
  • actions — with runAfter (object mapping predecessor action names to status arrays) and type for each action

Action Types

  • Switch — must have cases
  • If / Condition — must have actions (true branch) and optionally else.actions (false branch)
  • Foreach / Until — nest actions inside
  • ServiceProvider — with serviceProviderConfiguration
  • ApiConnection — only when no built-in ServiceProvider equivalent exists
  • InvokeFunction — for .NET local functions
  • Workflow / InvokeWorkflow — for calling child workflows

Preference: ServiceProvider over ApiConnection

Prefer ServiceProvider type with serviceProviderConfiguration over ApiConnection (managed connector) whenever a built-in equivalent exists. Built-in connectors run in-process with lower latency and no connection overhead.

Parameterization (keep it simple)

  • For Logic Apps Standard, prefer parameters.json for cross-environment values.
  • In workflow.json, reference values with @parameters('name').
  • In parameters.json, @appsetting('name') is the only valid expression type.
  • In connections.json, only @parameters(...) and @appsetting(...) are valid.
  • For more details, fetch Microsoft Learn docs about Standard parameters and app settings (create-parameters-workflows, edit-app-settings-host-settings).

3. SplitOn over ForEach

When a trigger returns an array (batch of messages), ALWAYS use splitOn on the trigger instead of wrapping actions in a For_each loop:

"triggers": {
  "myTrigger": {
    "splitOn": "@triggerOutputs()?['body']",
    ...
  }
}

SplitOn debatches the array so each item fires a separate workflow run. Only use For_each if splitOn is not supported by that trigger type.


4. File System Trigger Semantics

  • Do NOT add delete/remove/cleanup actions that remove the trigger input file by default.
  • The runtime does not re-trigger on the same unchanged file, so deleting is unnecessary unless the user explicitly requests archival/deletion behavior.

5. Trigger Output Verification (MANDATORY)

⚠️ NEVER assume a trigger returns file/message content directly. ALWAYS verify what the trigger actually returns.

Many triggers return metadata (file path, message ID, blob URI) rather than the actual content. You MUST check the trigger's return type from the reference workflow before building downstream actions.

5.1 Procedure

  1. After selecting a trigger via reference lookup (§1), read the reference workflow AND the reference docs to see what triggerOutputs() or triggerBody() actually contains.
  2. Call migration_readReferenceDoc with action="search" for the trigger's connector name to find documentation on its output schema and return type.
  3. Call migration_readReferenceDoc with action="read" on the top result to confirm the exact trigger output fields.
  4. If the trigger returns a file path (e.g. File System whenFilesAreAdded returns path and name), you MUST add a separate read content action (e.g. getFileContent) before any parsing/processing.
  5. If the trigger returns message content directly (e.g. HTTP Request trigger, Service Bus receiveQueueMessage), you can use triggerBody() directly.

5.2 Common Trigger Return Types

TriggerReturnsContent Available Via
File System whenFilesAreAddedFile metadata (path, name, size)Add getFileContent action with the path
File System whenFilesAreAddedOrModifiedFile metadata (path, name, size)Add getFileContent action with the path
Azure Blob whenABlobIsAddedOrModifiedBlob metadata (path, URI)Add readBlob action with the path
HTTP RequestFull request bodytriggerBody() directly
Service Bus receiveQueueMessageMessage content + propertiestriggerBody()?['contentData'] directly
Service Bus peekLockQueueMessagesV2Array of message metadataAdd completeMessage after processing
FTP/SFTP whenFileIsAddedFile metadataAdd getFileContent action with the path
Recurrence / TimerNo bodyN/A — use actions to fetch data

5.3 Rule

  • If trigger returns metadata/path: Add a content-reading action BEFORE any XmlParse, Parse JSON, Compose, or processing action.
  • If trigger returns content directly: Use triggerBody() or triggerOutputs()?['body'] in downstream actions.
  • If unsure: Check BOTH the reference workflow AND the reference docs. If the reference workflow has a read-content action after the trigger, or the docs show the trigger returns metadata rather than content, you need a content-reading action too.

6. 1:1 Flow to Workflow Rule

  • Every flow (including sub-processes with significant logic) MUST be a separate workflow.
  • Use the Workflow action type to invoke child workflows from parent workflows.
  • Do NOT convert flows to local functions.

7. Plan Adherence

When fixing any errors in workflow.json:

  • Do NOT deviate from the planned design.
  • Do NOT add/remove actions, change triggers, switch connectors, or alter schemas.
  • Before any fix, re-read the planning results to verify compliance.
  • If a fix requires changing the design, STOP and report to the user.

8. Scenario-Specific Action Overrides

These overrides are deterministic — apply them directly without asking the user.

8.1 XML Field Extraction

When extracting fields from an XML message body:

  1. FIRST: Use XmlParse built-in action with the schema from Artifacts/Schemas/. This validates and extracts XML fields in one step. Access fields via: body('Parse_XML')?['Root']?['fieldName']
  2. ONLY IF no schema exists and cannot be generated: fall back to xpath() expressions.

Do NOT use xpath() when an XSD schema is available — XmlParse is a level-1 built-in action and MUST be preferred over level-2 expressions per the Component Priority Ladder.

8.2 XML Schema Validation

When validating incoming XML against a schema:

  • Use XmlValidation built-in action — do NOT write custom validation logic or skip validation.

8.3 XML Transformation

When transforming XML documents:

  • Use Xslt (Transform XML) built-in action with maps from Artifacts/Maps/ — do NOT use Compose + string manipulation.

8.4 Output XML Construction

When constructing XML output documents:

  • FIRST: Use XmlCompose built-in action (XML Operations) to compose XML from structured data. This assembles XML output from structured fields.
  • XmlCompose can reference schemas from either the local Artifacts/Schemas/ folder or an Integration Account — select the source via the Source parameter (LogicApp or IntegrationAccount). If the flow uses the Integration Account model, use IntegrationAccount as the source.
  • If the source uses .NET code to build XML (e.g. XmlDocument, XElement) with complex business logic, use a .NET local function.
  • If the output is a simple static template with field substitution, Compose is acceptable.
  • Do NOT approximate XML construction with Compose + concat() when XmlCompose or a local function is more appropriate.

8.5 EDI Decode Output Handling

⚠️ CRITICAL: The EDIFACT EdifactDecode and X12 X12Decode built-in actions return JSON, not XML. If a downstream action or function expects XML (e.g. XmlDocument.LoadXml()), you MUST add an XmlCompose action after the decode action to convert the JSON back to XML using the appropriate message schema.

Pattern:

Decode_EDIFACT (EdifactDecode) → JSON output
  → Compose_EDIFACT_XML (XmlCompose, Source: IntegrationAccount, Schema: message schema) → XML output
    → downstream action expecting XML

Do NOT pass the JSON decode output directly to XML-expecting code. Do NOT try to parse the JSON as XML — it will fail with "Data at the root level is invalid".

8.6 JSON Parsing

When parsing JSON payloads:

  • Use Parse JSON built-in action — do NOT use json() expression for structured access.

9. Pre-Finalize Validation Checklist

Before storing workflow definitions, cross-check EVERY action against this table. If ANY row in the "DON'T" column matches your output, fix it before proceeding.

ScenarioDO (correct)DON'T (wrong — fix before storing)
Trigger output assumptionVerify trigger return type from refAssume trigger returns file/message content directly
File/Blob/FTP triggerAdd getFileContent/readBlob action after triggerUse triggerBody() for content (it only has metadata)
XML field extractionXmlParse action + schemaxpath() expression when schema exists
XML validationXmlValidation actionSkip validation or custom code
XML transformationXslt action + map fileCompose + string concat
XML output assemblyXmlCompose action (Source: LogicApp or IntegrationAccount)Compose + concat() for XML
EDI decode → XML neededAdd XmlCompose after EdifactDecode/X12DecodePass JSON decode output directly to XML-expecting code
Complex XML with .NET logic.NET local functionCompose + concat() approximation
JSON parsingParse JSON actionjson() expression for structured access
Array trigger debatchingsplitOn on triggerFor_each loop wrapping all actions
File trigger cleanupDo nothing (no delete)Delete/archive trigger input file
sub-process (via process-call)Separate workflow + Workflow actionMerge into parent or local function
Custom source code.NET local functionExpressions or inline approximation

More from Azure (Microsoft)

View publisher

© 2026 YourAI.tools. Every skill from an identity-verified publisher.

Independent catalog. Not affiliated with, endorsed by, or sponsored by Anthropic or any listed publisher. All trademarks belong to their respective owners.