Anti-Patterns
Overview
Section titled “Overview”Anti-patterns are recurring workflow design mistakes that lead to broken, inefficient, or unmaintainable workflows. The Workflow Management Flow (WMF) checks for these automatically during creation and editing.
Anti-Pattern Catalog
Section titled “Anti-Pattern Catalog”#1: Data Roundtrip
Section titled “#1: Data Roundtrip”Directive tells agent to collect data, then inputSchema asks agent to return that same data as structured output. The agent acts as a data-entry clerk copying from tool output to schema fields.
Detection: inputSchema mirrors the structure of data the agent was told to collect.
❌ Directive: "Get project info from package.json" inputSchema: { project_name: string, version: string, description: string } // Agent copies data from file to schema fields — pointless roundtrip
✅ Use expression node to extract data, or capture agent's ANALYSIS in inputSchema inputSchema: { architecture_assessment: string, risks_identified: string[] }#2: Empty InputSchema with Side Effects
Section titled “#2: Empty InputSchema with Side Effects”Node has no inputSchema but directive tells agent to perform side effects (create files, run commands). No evidence of what was done is captured.
Detection: Agent-directive node without inputSchema where directive describes actions with observable outcomes.
❌ Directive: "Create test files for auth module" (no inputSchema) // Workflow doesn't know what was created or if it succeeded
✅ inputSchema: { files_created: string[], tests_passing: boolean } // Evidence of completion captured in workflow context#3: Nested InitialData Format
Section titled “#3: Nested InitialData Format”System-level consideration. The engine stores variables as {description, value} objects. Not actionable at individual workflow level — follow the format the engine expects.
#4: Review Loop via InputSchema Instead of Files
Section titled “#4: Review Loop via InputSchema Instead of Files”Review feedback passed through inputSchema text fields instead of persistent files. Agent loses context between iterations.
Detection: Review/fix cycle where fix node receives feedback only via inputSchema text, not via persistent file.
❌ Review node → inputSchema: { feedback: string } → Fix node reads feedback from input // Feedback is ephemeral, lost on retry
✅ Review node writes review.md → Fix node reads review.md // Results persist across iterations and retries#5: Implicit Fix Loops
Section titled “#5: Implicit Fix Loops”Directive says “fix until done” without explicit loop structure in the graph. Agent retries internally without workflow control.
Detection: Words like “retry”, “keep trying”, “fix until” in directive without corresponding condition node creating a graph loop.
❌ Directive: "Keep fixing tests until they all pass" // No graph structure, agent loops internally without workflow control
✅ [fix] → [run-tests] → condition(passed?) → [fix] / [next] // Explicit graph loop with workflow visibility into each iteration#6: Unbounded Cycles
Section titled “#6: Unbounded Cycles”Validation loops without iteration limits or escalation paths. Can run forever if condition never met.
Detection: Cycle in graph without iteration counter variable or without condition checking iteration limit.
❌ Loop: [action] → [check] → [fix] → [action] (forever if quality never passes)
❌ Counter + limit but silent skip: expression(counter++) → condition(counter < max) → false → next-phase // Silently skips fix loop — user never knows issues were unresolved!
✅ Counter + limit + user decision: expression(counter++) → condition(counter < max) → false → ask-user-limit-reached // User decides: continue as-is / reset counter and retry / accept despite issuesThe false branch of a bounded loop limit check MUST route to a user decision node, not directly to the next phase. Options should include:
- continue/accept — proceed despite unresolved issues
- reset — reset counter to 0 and retry the fix loop
#7: Dynamic Data in Workflow Variables
Section titled “#7: Dynamic Data in Workflow Variables”Storing dynamic data generated during workflow execution (file contents, API responses, HTML output, extraction results) in workflow variables. These variables get injected into every directive via templates, bloating context with potentially unbounded content.
Detection: Variables that receive dynamic content through inputSchema during execution, especially content >1KB or content that grows unboundedly.
Scope: This anti-pattern applies to data flowing between workflow steps — NOT to static configuration stored in initialData at workflow start. See the Static Workflow Configuration pattern for the distinction.
❌ inputSchema: { html_content: string } Next directive: "Publish {{step.html_content}}" // Entire HTML page stored in variable, injected into every subsequent directive
❌ inputSchema: { extraction_results: object } Next directive: "Analyze {{extraction_results}}" // Potentially large extraction data round-tripped through variables
✅ Directive: "Save HTML to {{workspace_path}}/report.html" inputSchema: { file_path: string } Next directive: "Publish file at {{step.file_path}}" // Only the path stored in variable, agent reads file when neededException: Static instructional content in initialData (rules, standards, checklists) is a correct pattern, not variable abuse. These are deliberately placed to ensure the agent sees them on every relevant step. See Static Workflow Configuration.
#8: SystemReminder Modification
Section titled “#8: SystemReminder Modification”System-level consideration. systemReminder is static and applied to ALL steps. Step-specific instructions belong in node directives, not in systemReminder.
#9: Manual Index Management by Agent
Section titled “#9: Manual Index Management by Agent”Agent manually tracks array indices, counters, or pagination through inputSchema. Error-prone and breaks on retry.
Detection: inputSchema with fields like current_index, next_item_number, or counter values that agent must calculate.
❌ inputSchema: { current_index: number, next_item: string } // Agent calculates arithmetic, prone to errors
✅ Expression node: current_index = {current_index} + 1 Directive: "Process {{items[{current_index}]}}" // Workflow engine handles arithmetic deterministically#10: File Upload via Content
Section titled “#10: File Upload via Content”Passing entire workflow JSON through MCP tool parameters for large workflows. Hits size limits.
Detection: manage({ action: "create", workflow: <large JSON> }) with workflow >50KB.
❌ manage({ action: "create", workflow: <50KB JSON> }) // May hit parameter size limits
✅ token({ action: "upload" }) → HTTP PUT with file content // Token-based upload handles any size#11: Context Duplication
Section titled “#11: Context Duplication”Copying information already in agent’s context into workflow variables. Redundant and bloats context.
Detection: inputSchema that captures data the agent already has in conversation context (e.g., directory listings, project info from prior analysis).
❌ variable: project_structure = "<output of tree command>" // Agent already has this in context; storing it again wastes tokens
✅ Let agent re-read current data when needed. Store only stable references (paths, IDs).#12: Externalizing Critical Instructions to Files
Section titled “#12: Externalizing Critical Instructions to Files”Moving essential agent instructions and standards from initialData to external files, expecting the agent to read them each time. This creates risk of hallucination and adds unnecessary I/O.
Detection: Directive says “read rules from file X” for content that should be consistently available. Instructions that are critical for agent behavior stored outside the workflow.
❌ Directive: "Read planning standards from ./standards.md before creating plan" // Agent may skip reading, recall from training data, or read selectively // Extra I/O operation on every step that needs these rules
✅ Store in initialData variable: planning_standards = "1. Each step must... 2. Tests built-in..." Directive: "Create plan following {{planning_standards}}" // Workflow engine guarantees delivery; no I/O; no hallucination riskCorrect Patterns
Section titled “Correct Patterns”Dynamic Array Index Pattern
Section titled “Dynamic Array Index Pattern”The correct way to iterate over array items:
1. Store array: items = ["a", "b", "c"]2. Store index: current_index = 03. Directive: "Process item {{items[{current_index}]}}"4. Expression: current_index = {current_index} + 15. Condition: {current_index} < items.length → loop / continueFile-Based Review Pattern
Section titled “File-Based Review Pattern”[implement] → [review-to-file] → [check-issues] → [fix-from-file] → [review-to-file] ↓ no issues → [next]