Skip to content

Anti-Patterns

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.

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[] }

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

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

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

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 issues

The 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

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 needed

Exception: 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.

System-level consideration. systemReminder is static and applied to ALL steps. Step-specific instructions belong in node directives, not in systemReminder.

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

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

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 risk

The correct way to iterate over array items:

1. Store array: items = ["a", "b", "c"]
2. Store index: current_index = 0
3. Directive: "Process item {{items[{current_index}]}}"
4. Expression: current_index = {current_index} + 1
5. Condition: {current_index} < items.length → loop / continue
[implement] → [review-to-file] → [check-issues] → [fix-from-file] → [review-to-file]
no issues → [next]