Our review
Generates production-ready Azure Logic Apps workflows for enterprise integration patterns such as approvals, data syncs, batch processing, scheduled jobs, and event-driven automation.
Strengths
- Supports both Consumption (serverless) and Standard (single-tenant) plans
- Provides detailed Bicep and JSON workflow definitions
- Covers multiple triggers and connectors (HTTP, Service Bus, Office 365, etc.)
- Includes security settings like access control and VNet integration
Limitations
- Requires familiarity with Azure Logic Apps concepts
- Generated code may need customization for specific environments
- Does not handle deployment or CI/CD setup
When you need to quickly scaffold an Azure Logic App workflow with proper infrastructure as code and integration patterns.
When you need a no-code visual designer or when the logic is highly complex and better suited for traditional development.
Security analysis
CautionThe skill includes Bash as an allowed tool, introducing the potential for arbitrary command execution; while the primary purpose is to generate code, the Bash tool could be misused if a user prompts malicious commands.
- •Bash tool is allowed, which could be used to execute arbitrary commands without explicit restrictions.
Examples
Generate an Azure Logic Apps approval workflow triggered by an HTTP request that sends an approval email via Office 365 and writes the result to a SQL Server database.Create a Logic App that runs every hour, fetches new Salesforce leads, and syncs them to Azure SQL Database using the Salesforce connector and SQL Server connector.Generate a Logic App that is triggered by Azure Event Grid when a blob is added to a storage account, processes the file content, and sends a notification via Service Bus.name: azure-logic-apps description: Generate Logic Apps workflows with connectors, triggers, and integration patterns invocation: /azure-logic-apps [pattern] arguments:
- name: pattern description: "Pattern (approval, sync, batch, schedule, event)" required: false allowed_tools:
- Read
- Glob
- Grep
- Write
- Edit
- Bash
Instructions
You are an Azure Logic Apps integration expert. Generate production-ready Logic Apps workflows for enterprise integration patterns.
Step 1: Gather requirements
Determine from user input or $ARGUMENTS:
- Pattern: approval workflow, data sync, batch processing, scheduled job, event-driven
- Plan: Consumption (serverless, pay-per-execution) or Standard (single-tenant, dedicated)
- Triggers: HTTP request, recurrence, Event Grid, Service Bus, Blob Storage, email
- Connectors: Office 365, Salesforce, SAP, SQL Server, Dynamics 365, custom APIs
- Integration: B2B (EDI, AS2, X12), API-based, file-based
Step 2: Generate Consumption Logic App (serverless)
resource logicApp 'Microsoft.Logic/workflows@2019-05-01' = {
name: 'logic-${appName}-${environment}'
location: location
identity: {
type: 'SystemAssigned'
}
properties: {
state: 'Enabled'
definition: {
'$schema': 'https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#'
contentVersion: '1.0.0.0'
parameters: {
'$connections': {
defaultValue: {}
type: 'Object'
}
environment: {
defaultValue: environment
type: 'String'
}
}
triggers: {}
actions: {}
outputs: {}
}
parameters: {
'$connections': {
value: {}
}
}
accessControl: {
triggers: {
allowedCallerIpAddresses: [
{ addressRange: '10.0.0.0/8' }
]
}
contents: {
allowedCallerIpAddresses: [
{ addressRange: '10.0.0.0/8' }
]
}
}
}
tags: commonTags
}
Step 3: Generate Standard Logic App (single-tenant)
resource logicAppStandard 'Microsoft.Web/sites@2023-01-01' = {
name: 'logic-${appName}-${environment}'
location: location
kind: 'functionapp,workflowapp'
identity: {
type: 'SystemAssigned'
}
properties: {
serverFarmId: appServicePlan.id
siteConfig: {
netFrameworkVersion: 'v6.0'
appSettings: [
{ name: 'APP_KIND', value: 'workflowapp' }
{ name: 'AzureFunctionsJobHost__extensionBundle__id', value: 'Microsoft.Azure.Functions.ExtensionBundle.Workflows' }
{ name: 'AzureFunctionsJobHost__extensionBundle__version', value: '[1.*, 2.0.0)' }
{ name: 'AzureWebJobsStorage', value: storageConnectionString }
{ name: 'FUNCTIONS_EXTENSION_VERSION', value: '~4' }
{ name: 'FUNCTIONS_WORKER_RUNTIME', value: 'node' }
{ name: 'WEBSITE_NODE_DEFAULT_VERSION', value: '~18' }
]
ftpsState: 'Disabled'
minTlsVersion: '1.2'
vnetRouteAllEnabled: true
}
virtualNetworkSubnetId: logicAppSubnet.id
httpsOnly: true
}
tags: commonTags
}
// App Service Plan for Standard Logic App
resource appServicePlan 'Microsoft.Web/serverfarms@2023-01-01' = {
name: 'asp-logic-${appName}-${environment}'
location: location
sku: {
name: 'WS1' // WS1, WS2, WS3 (Workflow Standard)
tier: 'WorkflowStandard'
}
properties: {
zoneRedundant: true
}
}
Step 4: Generate workflow definitions
HTTP-triggered approval workflow:
{
"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#",
"contentVersion": "1.0.0.0",
"triggers": {
"When_a_HTTP_request_is_received": {
"type": "Request",
"kind": "Http",
"inputs": {
"schema": {
"type": "object",
"properties": {
"requestId": { "type": "string" },
"requestType": { "type": "string" },
"requestedBy": { "type": "string" },
"amount": { "type": "number" },
"description": { "type": "string" }
},
"required": ["requestId", "requestType", "requestedBy", "amount"]
}
}
}
},
"actions": {
"Initialize_status": {
"type": "InitializeVariable",
"inputs": {
"variables": [{
"name": "approvalStatus",
"type": "string",
"value": "Pending"
}]
},
"runAfter": {}
},
"Check_amount_threshold": {
"type": "If",
"expression": {
"and": [{
"greater": ["@triggerBody()?['amount']", 10000]
}]
},
"actions": {
"Send_VP_approval": {
"type": "ApiConnectionWebhook",
"inputs": {
"host": { "connection": { "name": "@parameters('$connections')['office365']['connectionId']" } },
"body": {
"NotificationUrl": "@{listCallbackUrl()}",
"Message": {
"To": "vp@company.com",
"Subject": "Approval Required: @{triggerBody()?['requestType']} - $@{triggerBody()?['amount']}",
"Options": "Approve, Reject",
"Body": "Request from @{triggerBody()?['requestedBy']}: @{triggerBody()?['description']}"
}
},
"path": "/approvalmail/$subscriptions"
}
},
"Set_VP_status": {
"type": "SetVariable",
"inputs": { "name": "approvalStatus", "value": "@body('Send_VP_approval')?['SelectedOption']" },
"runAfter": { "Send_VP_approval": ["Succeeded"] }
}
},
"else": {
"actions": {
"Send_manager_approval": {
"type": "ApiConnectionWebhook",
"inputs": {
"host": { "connection": { "name": "@parameters('$connections')['office365']['connectionId']" } },
"body": {
"NotificationUrl": "@{listCallbackUrl()}",
"Message": {
"To": "manager@company.com",
"Subject": "Approval Required: @{triggerBody()?['requestType']}",
"Options": "Approve, Reject"
}
},
"path": "/approvalmail/$subscriptions"
}
},
"Set_manager_status": {
"type": "SetVariable",
"inputs": { "name": "approvalStatus", "value": "@body('Send_manager_approval')?['SelectedOption']" },
"runAfter": { "Send_manager_approval": ["Succeeded"] }
}
}
},
"runAfter": { "Initialize_status": ["Succeeded"] }
},
"Update_database": {
"type": "ApiConnection",
"inputs": {
"host": { "connection": { "name": "@parameters('$connections')['sql']['connectionId']" } },
"method": "patch",
"path": "/v2/datasets/@{encodeURIComponent('default')}/tables/@{encodeURIComponent('[dbo].[Requests]')}/items/@{encodeURIComponent(triggerBody()?['requestId'])}",
"body": {
"Status": "@variables('approvalStatus')",
"ApprovedDate": "@utcNow()"
}
},
"runAfter": { "Check_amount_threshold": ["Succeeded"] }
},
"Send_notification": {
"type": "ApiConnection",
"inputs": {
"host": { "connection": { "name": "@parameters('$connections')['office365']['connectionId']" } },
"method": "post",
"path": "/v2/Mail",
"body": {
"To": "@triggerBody()?['requestedBy']",
"Subject": "Request @{variables('approvalStatus')}: @{triggerBody()?['requestType']}",
"Body": "<p>Your request has been <b>@{variables('approvalStatus')}</b>.</p>"
}
},
"runAfter": { "Update_database": ["Succeeded"] }
},
"Response": {
"type": "Response",
"inputs": {
"statusCode": 200,
"body": {
"requestId": "@triggerBody()?['requestId']",
"status": "@variables('approvalStatus')"
}
},
"runAfter": { "Send_notification": ["Succeeded"] }
}
}
}
Scheduled data sync workflow:
{
"triggers": {
"Recurrence": {
"type": "Recurrence",
"recurrence": {
"frequency": "Hour",
"interval": 1,
"timeZone": "Eastern Standard Time",
"schedule": {
"hours": ["8", "9", "10", "11", "12", "13", "14", "15", "16", "17"],
"minutes": [0]
}
}
}
},
"actions": {
"Get_records_from_Salesforce": {
"type": "ApiConnection",
"inputs": {
"host": { "connection": { "name": "@parameters('$connections')['salesforce']['connectionId']" } },
"method": "get",
"path": "/datasets/default/tables/Account/items",
"queries": {
"$filter": "LastModifiedDate ge @{addHours(utcNow(), -1)}"
}
},
"runAfter": {}
},
"For_each_record": {
"type": "Foreach",
"foreach": "@body('Get_records_from_Salesforce')?['value']",
"actions": {
"Upsert_to_SQL": {
"type": "ApiConnection",
"inputs": {
"host": { "connection": { "name": "@parameters('$connections')['sql']['connectionId']" } },
"method": "post",
"path": "/v2/datasets/@{encodeURIComponent('default')}/procedures/@{encodeURIComponent('[dbo].[UpsertAccount]')}",
"body": {
"AccountId": "@items('For_each_record')?['Id']",
"AccountName": "@items('For_each_record')?['Name']",
"LastModified": "@items('For_each_record')?['LastModifiedDate']"
}
}
}
},
"operationOptions": "Sequential",
"runtimeConfiguration": {
"concurrency": { "repetitions": 20 }
},
"runAfter": { "Get_records_from_Salesforce": ["Succeeded"] }
}
}
}
Step 5: Error handling patterns
Scope with try-catch:
{
"actions": {
"Try_scope": {
"type": "Scope",
"actions": {
"Process_data": {
"type": "Http",
"inputs": {
"method": "POST",
"uri": "https://api.example.com/process",
"body": "@triggerBody()",
"retryPolicy": {
"type": "exponential",
"count": 3,
"interval": "PT10S",
"minimumInterval": "PT5S",
"maximumInterval": "PT1H"
},
"authentication": {
"type": "ManagedServiceIdentity",
"audience": "https://api.example.com"
}
}
}
},
"runAfter": {}
},
"Catch_scope": {
"type": "Scope",
"actions": {
"Log_error": {
"type": "Http",
"inputs": {
"method": "POST",
"uri": "https://log-analytics-api.example.com/log",
"body": {
"workflowName": "@workflow().name",
"runId": "@workflow().run.name",
"error": "@result('Try_scope')",
"timestamp": "@utcNow()"
}
}
},
"Send_alert": {
"type": "ApiConnection",
"inputs": {
"host": { "connection": { "name": "@parameters('$connections')['teams']['connectionId']" } },
"method": "post",
"path": "/v1.0/teams/@{parameters('teamsChannelId')}/channels/@{parameters('alertChannelId')}/messages",
"body": {
"body": {
"content": "Logic App failure: @{workflow().name} - @{result('Try_scope')[0]['error']['message']}"
}
}
},
"runAfter": { "Log_error": ["Succeeded"] }
}
},
"runAfter": {
"Try_scope": ["Failed", "TimedOut"]
}
},
"Finally_scope": {
"type": "Scope",
"actions": {
"Update_audit_log": {
"type": "ApiConnection",
"inputs": {
"host": { "connection": { "name": "@parameters('$connections')['sql']['connectionId']" } },
"method": "post",
"path": "/v2/datasets/@{encodeURIComponent('default')}/tables/@{encodeURIComponent('[dbo].[AuditLog]')}/items",
"body": {
"WorkflowName": "@workflow().name",
"RunId": "@workflow().run.name",
"Status": "@if(equals(result('Try_scope')[0]['status'], 'Succeeded'), 'Success', 'Failed')",
"Timestamp": "@utcNow()"
}
}
}
},
"runAfter": {
"Try_scope": ["Succeeded", "Failed", "TimedOut", "Skipped"],
"Catch_scope": ["Succeeded", "Failed", "TimedOut", "Skipped"]
}
}
}
}
Step 6: Common workflow expressions
# String functions
@concat('Hello, ', triggerBody()?['name'])
@substring('Hello World', 0, 5) => 'Hello'
@replace('Hello World', 'World', 'Azure') => 'Hello Azure'
@toLower(triggerBody()?['email'])
@split('a,b,c', ',') => ['a','b','c']
# Date/time functions
@utcNow() => '2024-01-15T10:30:00Z'
@addDays(utcNow(), 7) => 7 days from now
@formatDateTime(utcNow(), 'yyyy-MM-dd') => '2024-01-15'
@convertTimeZone(utcNow(), 'UTC', 'Eastern Standard Time')
# Collection functions
@length(body('Get_items')?['value']) => count of items
@first(body('Get_items')?['value']) => first item
@last(body('Get_items')?['value']) => last item
@contains(createArray('a','b','c'), 'b') => true
# Control flow
@if(equals(variables('status'), 'Approved'), 'Yes', 'No')
@coalesce(triggerBody()?['name'], 'Unknown')
@empty(triggerBody()?['items']) => true if null/empty
# JSON functions
@json('{"key":"value"}')
@xml(body('Get_response'))
@base64(triggerBody()?['file'])
# Workflow functions
@workflow().name => Logic App name
@workflow().run.name => Run ID
@actions('action_name').outputs.statusCode
@result('scope_name') => scope execution results
Step 7: Generate Terraform configuration
# Consumption Logic App
resource "azurerm_logic_app_workflow" "main" {
name = "logic-${var.app_name}-${var.environment}"
location = azurerm_resource_group.main.location
resource_group_name = azurerm_resource_group.main.name
identity {
type = "SystemAssigned"
}
workflow_parameters = {
"$connections" = jsonencode({
defaultValue = {}
type = "Object"
})
}
access_control {
trigger {
allowed_caller_ip_address_range = ["10.0.0.0/8"]
}
content {
allowed_caller_ip_address_range = ["10.0.0.0/8"]
}
}
tags = var.common_tags
}
# HTTP trigger
resource "azurerm_logic_app_trigger_http_request" "main" {
name = "http-trigger"
logic_app_id = azurerm_logic_app_workflow.main.id
schema = jsonencode({
type = "object"
properties = {
requestId = { type = "string" }
data = { type = "object" }
}
})
}
# Recurrence trigger
resource "azurerm_logic_app_trigger_recurrence" "daily" {
name = "daily-trigger"
logic_app_id = azurerm_logic_app_workflow.main.id
frequency = "Day"
interval = 1
time_zone = "Eastern Standard Time"
schedule {
at_these_hours = [8]
at_these_minutes = [0]
}
}
# HTTP action
resource "azurerm_logic_app_action_http" "call_api" {
name = "call-api"
logic_app_id = azurerm_logic_app_workflow.main.id
method = "POST"
uri = "https://api.example.com/process"
body = jsonencode({
data = "@triggerBody()"
})
headers = {
"Content-Type" = "application/json"
}
run_after {}
}
# Standard Logic App
resource "azurerm_logic_app_standard" "main" {
name = "logic-std-${var.app_name}-${var.environment}"
location = azurerm_resource_group.main.location
resource_group_name = azurerm_resource_group.main.name
app_service_plan_id = azurerm_service_plan.logic.id
storage_account_name = azurerm_storage_account.logic.name
storage_account_access_key = azurerm_storage_account.logic.primary_access_key
virtual_network_subnet_id = azurerm_subnet.logic.id
identity {
type = "SystemAssigned"
}
site_config {
dotnet_framework_version = "v6.0"
vnet_route_all_enabled = true
min_tls_version = "1.2"
ftps_state = "Disabled"
elastic_instance_minimum = 1
app_scale_limit = 10
runtime_scale_monitoring_enabled = true
}
app_settings = {
"FUNCTIONS_EXTENSION_VERSION" = "~4"
"FUNCTIONS_WORKER_RUNTIME" = "node"
"WEBSITE_NODE_DEFAULT_VERSION" = "~18"
}
tags = var.common_tags
}
Step 8: Monitoring and diagnostics
resource diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = {
name: 'logic-diagnostics'
scope: logicApp
properties: {
workspaceId: logAnalyticsWorkspace.id
logs: [
{ category: 'WorkflowRuntime', enabled: true }
]
metrics: [
{ category: 'AllMetrics', enabled: true }
]
}
}
Key metrics:
RunsStarted/RunsCompleted/RunsFailed- Workflow execution statsRunLatency- End-to-end workflow durationActionLatency- Individual action durationTriggersFired/TriggersSucceeded/TriggersFailed- Trigger healthBillableActionExecutions/BillableTriggerExecutions- Cost tracking
Consumption vs Standard comparison
| Feature | Consumption | Standard | |---------|-------------|----------| | Hosting | Serverless, multi-tenant | Single-tenant, App Service | | Pricing | Pay per execution | Fixed plan cost | | VNET | Not supported | Full VNET integration | | Workflows | One per Logic App resource | Multiple per Logic App | | Stateful/Stateless | Stateful only | Both stateful and stateless | | Deployment slots | No | Yes | | Local development | No | VS Code extension | | Scale | Automatic | Configurable (1-10+ instances) | | SLA | 99.9% | 99.95% |
Best practices
- Use Standard for production - VNET integration, deployment slots, better isolation
- Implement error handling - Use scopes for try-catch-finally patterns
- Use managed identity - Authenticate to Azure services without connection strings
- Parameterize workflows - Use parameters for environment-specific values
- Enable diagnostic logging - Send logs to Log Analytics for monitoring
- Use tracked properties - Add custom tracking data to action outputs for querying
- Limit connector permissions - Use API connections with least-privilege credentials
- Implement retry policies - Configure exponential backoff for transient failures
- Use concurrency control - Set
runtimeConfiguration.concurrency.repetitionson loops - Version workflows - Use ARM/Bicep templates in source control
Anti-patterns
- Deeply nested conditions - Use Switch actions or separate child workflows
- Large payloads in workflow state - Use Blob Storage for files; pass references only
- Polling triggers for real-time needs - Use webhook or push-based triggers
- Single monolithic workflow - Break into child workflows for maintainability
- Hardcoded connection strings - Use Key Vault references and managed identity
- Ignoring run history limits - Consumption retains 90 days; archive if needed
- Synchronous long-running operations - Use async patterns with webhooks
- Using Consumption for high-frequency triggers - Cost can exceed Standard plan
Security considerations
- Restrict trigger access with IP allowlists (
accessControl.triggers) - Use managed identity for all Azure service connections
- Secure inputs/outputs with obfuscation (
runtimeConfiguration.secureData) - Store secrets in Key Vault, not workflow parameters
- Enable HTTPS-only for Standard Logic Apps
- Use private endpoints for VNET-connected Logic Apps (Standard)
- Audit with Azure Monitor and Log Analytics
- Control access with Azure RBAC (Logic App Contributor, Logic App Operator)
Cost optimization
- Consumption: Monitor billable executions; optimize loops and conditions to reduce action count
- Standard: Right-size the App Service Plan; use auto-scale rules
- Reduce polling frequency: Use longer intervals or event-based triggers
- Use built-in connectors: They cost less than managed/enterprise connectors
- Avoid unnecessary actions: Combine expressions instead of using multiple Compose actions
- Use stateless workflows (Standard): Lower overhead for request-response patterns
- Archive run history: Configure retention to manage storage costs
- Disable unused workflows: Stop workflows that are not actively needed
Next.js App Router Expert
Development
A skill that turns Claude into a Next.js App Router expert.
README Generator
Development
Creates professional and comprehensive README.md files for your projects.
API Documentation Writer
Development
Generates comprehensive API documentation in OpenAPI/Swagger format.