OpenFang Automated Workflow Setup Guide

9 min read

A single agent can only do so much; true end-to-end automation requires orchestrating multiple agents. This guide walks you through four complete use cases—Daily Industry Briefings (simple pipeline), Competitor Monitoring & Alerts (fan-out + conditional branching), Content Production Pipelines (multi-agent collaboration), and Customer Support Triage (conditional routing)—to help you master the full power of the OpenFang workflow engine.

OpenFang Automated Workflow Setup Guide: From Single Agent to Agent Teams

Slug: openfang-workflow-automation-guide Category: usage-guides Target Keywords: OpenFang workflow, OpenFang automation process, OpenFang Multi-Agent orchestration Search Intent: Informational (users looking to build complex agent automation processes) Target Word Count: ~2000 words Language: en


Why Do You Need Workflows?

The tasks a single agent can complete are limited. When you need an end-to-end process like "Research a topic → Write an article → Fact-check → Publish → Monitor feedback," you need to orchestrate multiple agents into a workflow.

OpenFang's workflow engine supports three orchestration modes: Pipeline (serial), Fan-out (parallel), and Conditional (branching). You can combine Hands and Agents like LEGO bricks to build complex automation processes.

This article will take you from simple to complex scenarios through four practical cases to help you master OpenFang workflow construction.

Core Workflow Concepts

Before diving into the cases, let's understand a few core concepts:

ConceptDescription
TaskThe smallest execution unit in a workflow; a Task corresponds to a Hand or an Agent
PipelineChains multiple Tasks, where the output of the previous Task automatically becomes the input for the next
Fan-outDistributes work to multiple Agents for parallel processing, then aggregates the results
TriggerThe event source that initiates a workflow: scheduled, Webhook, file changes, or message commands
ContextShared state passed between workflow steps, similar to variable scope in programming languages

Case 1: Daily Industry Briefing (Simple Pipeline)

This is the simplest Pipeline workflow—automatically generating an industry briefing every morning:

toml
[[workflows]]name = "daily_industry_briefing"description = "Generate a daily industry news briefing at 8 AM"[workflows.trigger]type = "schedule"cron = "0 8 * * 1-5"             # 8 AM on weekdays[[workflows.tasks]]id = "monitor"hand = "collector"config = { keywords = ["AI agent", "Rust framework"], sources = ["news", "github"] }timeout = 300[[workflows.tasks]]id = "summarize"hand = "researcher"config = { depth = "shallow", focus = "summary" }depends_on = ["monitor"]timeout = 600[[workflows.tasks]]id = "notify"channel = "slack"config = { channel = "#industry-news", format = "rich_text" }depends_on = ["summarize"][workflows.output]format = "slack_message"save_to = "workspace/briefings/{{date}}.md"

The workflow execution flow is: Collector (gather) → Researcher (summarize) → Slack (notify). depends_on defines the dependencies between Tasks.

Case 2: Competitor Monitoring & Alerts (Parallel + Aggregation)

This workflow monitors multiple competitor sites simultaneously and aggregates the results for analysis:

toml
[[workflows]]name = "competitor_monitor"description = "Monitor 5 competitor sites in parallel and send alerts on changes"[workflows.trigger]type = "schedule"cron = "0 */6 * * *"# Stage 1: Parallel Collection (Fan-out)[[workflows.tasks]]id = "check_competitor_a"hand = "collector"config = { target = "competitor-a.com", mode = "diff" }[[workflows.tasks]]id = "check_competitor_b"hand = "collector"config = { target = "competitor-b.com", mode = "diff" }[[workflows.tasks]]id = "check_competitor_c"hand = "collector"config = { target = "competitor-c.com", mode = "diff" }# Stage 2: Aggregation (Wait for all collections to finish)[[workflows.tasks]]id = "aggregate"hand = "researcher"config = { action = "merge_and_prioritize" }depends_on = ["check_competitor_a", "check_competitor_b", "check_competitor_c"]# Stage 3: Conditional Logic — Notify only if there are significant changes[[workflows.tasks]]id = "check_significance"hand = "predictor"config = { action = "assess_impact" }depends_on = ["aggregate"]# Stage 4: Conditional Notification[[workflows.tasks]]id = "alert_high"channel = "telegram"config = { chat_id = "-100xxx", priority = "high" }depends_on = ["check_significance"]condition = "ctx.significance_score > 0.7"[[workflows.tasks]]id = "alert_low"channel = "email"config = { to = "[email protected]", priority = "low" }depends_on = ["check_significance"]condition = "ctx.significance_score <= 0.7"

Key patterns here:

  • Fan-out: The 5 collection Tasks in Stage 1 run in parallel; no depends_on required.
  • Barrier: The Aggregate Task in Stage 2 waits for all 5 collection Tasks to complete.
  • Conditional: Stage 4 selects different notification channels based on the significance score.

Case 3: Content Production Pipeline (Multi-Agent Collaboration)

This is a classic multi-agent collaboration scenario—AI writing, AI fact-checking, and AI image generation:

toml
[[workflows]]name = "content_pipeline"description = "Fully automated content production from topic to publication"[workflows.trigger]type = "webhook"endpoint = "/webhook/content/new"secret = "${WEBHOOK_SECRET}"# Stage 1: Research[[workflows.tasks]]id = "research"hand = "researcher"config = {  depth = "deep",  source_types = ["academic", "news", "social"],  target_length = "3000_words"}timeout = 900# Stage 2: Drafting (Using different models)[[workflows.tasks]]id = "draft"hand = "researcher"              # Reuse Researcher Hand with a different promptconfig = {  model = "claude-opus-4-8",  instruction = "draft_article",  style = "professional_yet_approachable"}depends_on = ["research"]# Stage 3: Fact Checking[[workflows.tasks]]id = "fact_check"hand = "researcher"config = {  model = "claude-haiku-4-5",   # Use a faster model for checking  action = "verify_claims",  strictness = "high"}depends_on = ["draft"]# Stage 4: Cover Image Generation[[workflows.tasks]]id = "generate_cover"hand = "clip"config = {  action = "generate_cover_image",  style = "modern_tech",  resolution = "1280x720"}depends_on = ["draft"]           # Does not depend on fact-checking, can run in parallel# Stage 5: SEO Optimization[[workflows.tasks]]id = "seo_optimize"hand = "researcher"config = { action = "seo_optimize", target_keyword = "{{.keyword}}" }depends_on = ["fact_check"]# Stage 6: Publish[[workflows.tasks]]id = "publish"channel = "webhook"config = { url = "{{.cms_endpoint}}", method = "POST" }depends_on = ["seo_optimize", "generate_cover"]# Stage 7: Promotion[[workflows.tasks]]id = "promote"channel = "twitter"config = { action = "post_thread", hashtags = ["#AI", "#Automation"] }depends_on = ["publish"]

Note that generate_cover in Stage 4 depends only on draft and not on fact_check—this means image generation and fact-checking run in parallel, reducing total wait time.

Case 4: Customer Support Triage (Conditional Routing)

This is an intelligent customer support workflow that routes issues to different processes based on the intent:

toml
[[workflows]]name = "support_triage"description = "Intelligent support: Classify → Route → Handle → Escalate"[workflows.trigger]type = "message"channel = "whatsapp"pattern = "/help *"# Classification[[workflows.tasks]]id = "classify"hand = "researcher"config = {  model = "claude-haiku-4-5",  action = "classify_intent",  categories = ["billing", "technical", "feature_request", "complaint"]}# Billing → Query System[[workflows.tasks]]id = "handle_billing"channel = "webhook"config = { url = "https://billing-api.company.com/lookup" }depends_on = ["classify"]condition = "ctx.intent == 'billing'"# Technical → Knowledge Base Search[[workflows.tasks]]id = "search_kb"hand = "researcher"config = { action = "search_knowledge_base", max_results = 3 }depends_on = ["classify"]condition = "ctx.intent == 'technical'"# Feature Request → Log to Product Board[[workflows.tasks]]id = "log_feature"channel = "webhook"config = { url = "https://productboard-api.company.com/notes" }depends_on = ["classify"]condition = "ctx.intent == 'feature_request'"# Complaint → Escalate to Human[[workflows.tasks]]id = "escalate"channel = "slack"config = { channel = "#urgent-support", mention = "@oncall" }depends_on = ["classify"]condition = "ctx.intent == 'complaint'"# Final Reply[[workflows.tasks]]id = "reply"channel = "whatsapp"config = { reply_to = "{{.original_message.id}}" }depends_on = ["handle_billing", "search_kb", "log_feature", "escalate"]

Workflow Debugging & Testing

Before production deployment, we recommend using Dry Run mode to test your workflow:

bash
# Dry run (does not execute external actions)openfang workflow run competitor_monitor --dry-run# Run only up to a specific Taskopenfang workflow run content_pipeline --until draft# View workflow execution historyopenfang workflow history competitor_monitor --limit 10# View detailed logs for a specific executionopenfang workflow inspect competitor_monitor --run-id abc123

Workflow Best Practices

  1. Set reasonable timeouts: Every Task should have a timeout to prevent a single step from stalling the entire process.
  2. Add retry mechanisms: Configure retry = 3 with exponential backoff for network-related Tasks.
  3. Use conditions: Avoid unnecessary Task execution to save on API costs.
  4. Log execution details: Configure log_level = "debug" for troubleshooting.
  5. Monitor workflow health: Integrate workflow metrics with Prometheus/Grafana.

FAQ

How many Tasks can a single workflow support?
There is no hard limit. However, we recommend keeping a single workflow under 20 Tasks for maintainability. More complex processes should be broken down into sub-workflows.
How do I handle Task execution failures?
Each Task can have an independent failure policy:

``toml
[workflows.tasks.fallback]
on_failure = "continue" # continue / retry / abort / escalate
retry_count = 3
retry_delay_seconds = 60
fallback_task = "manual_review" # Fallback Task after failure
``

Can workflows call each other?
Yes. Using trigger.type = "workflow" allows one workflow to trigger another. Combined with conditions, you can implement complex nested logic.
How do I pass dynamic parameters in a workflow?
Use the template syntax {{.variable_name}}. Context variables can originate from trigger data, the output of previous Tasks, or global configuration variables.

Next Steps