Imported from yoloyolo8/dify-workflow-writer (
SKILL.md). Install upstream withnpx skills add yoloyolo8/dify-workflow-writer. Copyright stays with the author.
Dify Workflow Writer
Expert skill for writing production-ready Dify workflow DSL files.
Trigger Conditions
Activate this skill when:
- User asks to create a Dify workflow
- User needs to modify or debug a Dify DSL file
- User wants to add nodes to an existing workflow
- User mentions "Dify", "workflow DSL", or "工作流"
Quick Reference
DSL Structure Overview
app: # App metadata
name: "Workflow Name"
description: "Description"
mode: workflow # Always "workflow" for workflows
icon: sparkle # Emoji or icon name
icon_background: '#D3F8DF'
dependencies: [] # Plugin dependencies (e.g., gemini, openai)
kind: app
version: 0.2.0
workflow:
environment_variables: [] # Environment variables
conversation_variables: [] # Conversation state
features: {} # File upload, TTS, etc.
graph:
nodes: [] # Node definitions
edges: [] # Node connections
viewport: {} # Canvas position
🔴 Critical Rules
Rule 1: Variable Reference Syntax
The most common mistake. Always use double # symbols:
❌ WRONG: {{1718352852007.text}}
❌ WRONG: {{#1718352852007.text}} (missing closing #)
❌ WRONG: {{{#1718352852007.text#}}} (triple braces)
✅ CORRECT: {{#1718352852007.text#}}
Variable reference format: {{#NODE_ID.VARIABLE_NAME#}}
Rule 2: Code Node Outputs Must Be Defined
Every output variable MUST be declared in the outputs schema:
# ❌ WRONG: Missing outputs definition
- data:
code: |
def main(input):
return {"result": input.upper()}
type: code
# ✅ CORRECT: Outputs properly defined
- data:
code: |
def main(input):
return {"result": input.upper()}
code_language: python3
outputs:
result:
type: string
children: null
type: code
Rule 3: Reserved Variable Names
Never use error as an output variable name - it conflicts with system error handling:
# ❌ WRONG
def main(data):
return {"error": "something went wrong"} # Causes JS execution error
# ✅ CORRECT
def main(data):
return {"error_message": "something went wrong"}
Rule 4: Node ID Format
Node IDs are Unix timestamps (milliseconds). Generate unique IDs:
# Example: Current timestamp as ID
id: '1718352852007' # Must be quoted string
Rule 5: Edge Connection Format
Edges connect nodes via source → target:
edges:
- id: 1718352852007-source-1719356422842-target
source: '1718352852007' # From node
sourceHandle: source # Output handle
target: '1719356422842' # To node
targetHandle: target # Input handle
type: custom
data:
sourceType: start
targetType: llm
For IF/ELSE branches, use sourceHandle: 'true' or sourceHandle: 'false'.
Node Types Reference
Start Node (Required)
- data:
type: start
title: Start
desc: "Input parameters"
variables:
- variable: input_text # Variable name
label: "Input Text" # Display label
type: text-input # text-input | paragraph | number | select
required: true
max_length: 1000
options: [] # For select type
id: '1718352852007'
type: custom
position: { x: 30, y: 275 }
width: 244
height: 118
End Node (Required)
- data:
type: end
title: End
desc: "Output results"
outputs:
- variable: result
value_selector:
- '1719444170368' # Source node ID
- text # Source variable
id: '1718356146046'
type: custom
position: { x: 1550, y: 275 }
LLM Node (90% of workflows)
- data:
type: llm
title: "Analyze Content"
desc: "Use LLM to analyze"
model:
provider: langgenius/openai/openai # or langgenius/gemini/google
name: gpt-4o # Model name
mode: chat
completion_params: {}
prompt_template:
- id: system-prompt-id
role: system
text: |
You are a helpful assistant.
Analyze the following content.
- id: user-prompt-id
role: user
text: |
Content: {{#1719357159255.content#}}
Please analyze this.
context:
enabled: false
variable_selector: []
vision:
enabled: false
id: '1718355814693'
type: custom
position: { x: 942, y: 275 }
Code Node
- data:
type: code
title: "Parse JSON"
desc: "Parse API response"
code_language: python3
code: |
import json
def main(json_body):
if not json_body:
return {"success": "false"}
try:
data = json.loads(json_body)
return {
"success": "true",
"content": data.get("content", "")
}
except Exception:
return {"success": "false"}
variables:
- variable: json_body # Parameter name in main()
value_selector:
- '1719356422842' # Source node ID
- body # Source variable
outputs:
success:
type: string
children: null
content:
type: string
children: null
id: '1719357159255'
type: custom
position: { x: 638, y: 275 }
HTTP Request Node
- data:
type: http-request
title: "Fetch Data"
desc: "Call external API"
method: get # get | post | put | delete
url: https://api.example.com/data
params: "id:{{#1718352852007.input_id#}}"
headers: "Authorization:Bearer {{#env.API_KEY#}}"
body:
type: none # none | json | form-data | raw
data: []
authorization:
type: no-auth # no-auth | api-key | bearer
config: null
timeout:
max_connect_timeout: 0
max_read_timeout: 0
max_write_timeout: 0
retry_config:
retry_enabled: true
max_retries: 3
retry_interval: 100
id: '1719356422842'
type: custom
position: { x: 334, y: 275 }
IF/ELSE Node
- data:
type: if-else
title: "Check Condition"
desc: "Branch based on condition"
cases:
- id: 'true'
case_id: 'true'
logical_operator: and
conditions:
- id: 'condition-1'
variable_selector:
- '1719357159255'
- success
comparison_operator: is # is | is-not | contains | gt | lt | etc.
value: 'true'
varType: string
id: '1720855943817'
type: custom
position: { x: 942, y: 275 }
Workflow Patterns
Pattern 1: Simple LLM Processing
Start → LLM → End
Use for: Single-step text generation, translation, summarization.
Pattern 2: HTTP + LLM Pipeline
Start → HTTP Request → Code (Parse) → IF/ELSE → LLM → End
↓
End (Error)
Use for: Fetching external data, processing with LLM.
Pattern 3: Multi-LLM Chain (Reflection)
Start → LLM (Analyze) → LLM (Review) → LLM (Refine) → End
Use for: High-quality content generation with self-reflection.
Pattern 4: Conditional Branching
Start → LLM (Classify) → IF/ELSE → LLM (Path A) → End
↓
LLM (Path B) → End
Use for: Intent routing, multi-path processing.
Common Gotchas
See references/common-gotchas.md for detailed troubleshooting.
Top 5 Mistakes
- Variable syntax - Missing
#symbols - Code outputs not defined - Every return field needs schema
- Using
errorvariable - Reserved name, causes crashes - Edge connections incomplete - Missing edges = broken workflow
- Node ID collisions - Each ID must be unique timestamp
Best Practices
Debugging
# Enable retry for fault tolerance
retry_config:
retry_enabled: true
max_retries: 3
retry_interval: 100
Version Compatibility
- Use Dify 0.13.0+ for parallel tasks, session variables
- Use Dify 1.5.0+ for "Last Run" debugging feature
- Check plugin dependencies before import
Security
- Never hardcode API keys in DSL
- Use environment variables:
{{#env.API_KEY#}} - Export with caution - secrets may be included
File References
references/variable-syntax.md- Complete variable syntax guidereferences/node-templates.md- All node type templatesreferences/common-gotchas.md- Troubleshooting guidetemplates/minimal-workflow.yaml- Starter templatetemplates/llm-chain-workflow.yaml- Multi-LLM patterntemplates/http-llm-workflow.yaml- API + LLM pattern
