Modularization and Reuse
Publish the complete workflow as a module, and then reuse it through the input/output contract and version strategy of sub_workflow.
When you reach the second and third workflows, you will find that a certain piece of logic appears repeatedly - pulling ASA data, sending Slack messages, and generating Excel reports. If you continue to copy and paste, you will have to change three places to change one place, the test will be repeated, and the version will be out of control. It’s time to do modularization at this time.
Template = a snapshot of the starting document, which evolves independently after cloning; module = a sub-process that can be referenced, and the caller will automatically benefit after the upgrade. The two are not substitutes, but complementary. This page talks about modules.
What Is A "Module"
A module is essentially a complete workflow with a module contract. The contract additionally discloses:
- inputs — Parameters that the caller must pass in (with name, type, required, default value, description)
- outputs — The structured result generated after execution (can be directly referenced by the caller)
- version — Semantic version number to facilitate caller locking
name: my-team-text-formatter
version: "1.0.0"
module:
enabled: true
display_name: "团队文本格式化"
contract_version: "1.0.0"
inputs:
- name: text
type: string
required: true
maps_to_variable: text
- name: prefix
type: string
required: false
default: "[INFO]"
maps_to_variable: prefix
outputs:
- name: formatted_text
type: string
source: "{{var:formatted_text}}"
variables:
text: ""
prefix: "[INFO]"
formatted_text: ""
workflow:
- step: format_text
code:
language: python
script: |
import os
prefix = os.environ.get("WF_VAR_PREFIX", "[INFO]")
text = os.environ.get("WF_VAR_TEXT", "")
print(f"FORMATTED={prefix} {text}")
extract:
- pattern: 'FORMATTED=(.*)'
variable: formatted_text
idempotent: trueAfter having the contract, the sub_workflow step of the caller (parent workflow) will:
- Check required input, output mappings and references when editing and validating;
- The runtime passes in inputs in a separate sub-execution scope and returns only explicitly mapped outputs;
- The editor can display input, output and version information according to the contract.
How the Parent Workflow Calls the Module
workflow:
- step: build_report
agent: writer
input: "生成今日运营摘要"
- step: format_report
sub_workflow:
name: my-team-text-formatter
version_strategy: range
version_range: "^1.0.0"
inputs:
text: "{{steps.build_report.output}}"
prefix: "[日报]"
outputs:
formatted_text: formatted_text
depends_on:
- build_report
- step: save_result
agent: writer
depends_on:
- format_report
input: "请检查并整理:{{formatted_text}}"Key points:
nameFill in the module workflow name, or select a specific workflow in the editor.inputscorresponds to the input name in the module contract.outputsThe left side is the parent workflow variable, and the right side is the output name exposed by the module; after the call is completed, the parent variable is directly referenced.- The module output in the example is available via
{{formatted_text}}Read.
Turn Existing Workflows Into Modules: Promote to Module
The current "Promote to module" applies to the entire workflow and will not be automatically extracted from the selected steps in the canvas. Process:
- First organize the logic to be reused into a workflow with clear boundaries and save it.
- Select "Promote to module" in the editor's More menu or workflow settings.
- In the pop-up window:
- Fill in the display name, description, classification and contract version;
- Declare the values that need to be passed in from the parent workflow as inputs;
- Declare the results that the parent workflow is allowed to read as outputs, and fill in the source for each output.
- After saving, this workflow will appear as a module in the module library; the original workflow content will not be replaced or deleted.
Modules can be understood as functions with public parameters and return values. Currently, it is necessary to organize the target logic into a complete workflow, and then upgrade the entire workflow into a module.
Module Upgrade and Version Compatibility
The module contract has contract_version, and the parent workflow can be selected in sub_workflow:
version_strategy: latest— Use the latest version currently parsable.version_strategy: pinned+pinned_version— Lock a specific version.version_strategy: range+version_range— Resolved by version range.
What is a "compatible change"?
- ✓ Add an optional input (required/default values are not considered broken)
- ✓ Add an output field
- ✗ Delete/rename input
- ✗ Delete/rename output
- ✗ Change input type
When making changes that break compatibility, the semantic version should be upgraded to the next MAJOR. The platform does not enforce, but is protected when the caller locks ^X.Y.Z.
Loop Detection
Module A cannot indirectly reference itself. The platform performs detection on two levels:
- Static detection at release time — When saving a module, DFS scans the dependency graphs of all other modules it references and refuses to save if there are loops.
- Runtime dynamic detection — If a cycle resolved by the runtime occurs during execution (for example, it is referenced after a conditional branch), an error will be thrown immediately.
Maximum recursion depth depends on the plan: Free does not support sub_workflow; Pro allows 3 levels, Team 5, and Enterprise 8. This is the depth of the parent → child → grandchild call chain, not the number of fan-out calls at one level.
Variable Isolation
The module runs as a "child WorkflowExecutionContext", completely isolated from the parent context:
- The parent's variables/steps outputs/agents are not inherited to the child by default;
- The child's internal step output will not overflow to the parent - the parent can only see the outputs declared in the contract;
- The only way to pass data across parent and child is inputs / outputs (explicit contract).
If a sub-workflow requires Agent or knowledge base inheritance, you should use the explicit inheritance configuration provided by sub_workflow and do not rely on implicit sharing.
Demote from module: Change the module back to normal workflow
Demote will unmark the module of the current workflow and return it to the normal workflow; it will not automatically expand the module steps to each caller.
- Open the module itself and select "Downgrade to normal workflow" in the workflow settings, which can also be entered from the operation menu of the workflow list;
- If there is a parent workflow that references the module, the system will list the references and prevent direct downgrade;
- Only confirm that these callers have been adjusted before continuing. Forced downgrade will not rewrite the parent workflow for you, and the original sub_workflow reference may become invalid at runtime.
Downgrading does not delete the workflow content; it simply removes the module contract and module identity. Built-in modules cannot be downgraded.
Where to Manage All Modules
The main navigation "Module Library" on the left displays the modules available for the current account. Depending on the module source, it can be:
- Browse and search modules, then filter or sort them by the fields available in the current UI;
- Instantiate the Market module as an editable workflow, or update references in the library when there is a new version of the Market;
- Uninstall the downloaded market module; before uninstalling, you need to confirm that no workflow still refers to it by name;
- For the module you promoted, maintain the contract in the original workflow settings or downgrade it to a normal workflow. There are currently no module ownership transfer operations.
When To Make Modules
- ✓ The same piece of logic appears in more than 2 workflows
- ✓ A logically stable and clear external contract (typically "sending messages/checking reports/generating Markdown")
- ✓ A single workflow has exceeded 15 steps, and its readability has decreased.
- ✗ A piece of logic is only used once and will not be reused in the future - directly inlined
- ✗ A small utility function of 2–3 lines - code reuse using code steps is more natural than modules
Next
- Built-In Module Library — Familiar with the calling method of sub_workflow according to the current module library list
- Step Types and Enhancements — Full field reference for sub_workflow in
- Best Practices — "When and how to dismantle"