Imported from 1DivSin/workflow (
src/SKILL.md). Install upstream withnpx skills add 1DivSin/workflow --skill src. Copyright stays with the author.
Workflow
Workflow is the formal-language workflow system defined by
grammar/FusionFlow.g4. This skill authors and runs its declarative programs in
psi-agent. The workspace tool compiles source into Core IR, lowers it to a
WorkflowGraph, executes a checked plan, runs Agent-backed Steps in ephemeral
Sessions, runs Program-backed Steps through specialized Program Agents with
structured process capture, and checkpoints Human-backed Steps across turns.
Workspace boundary. Store one-off authored G4 files under the workspace-managed
flows/directory. Reusable declarations have one canonical bundle:flows/workflows/<slug>/, containing<slug>.workflowor<slug>.g4(.workflowtakes precedence if both exist). The skill ships no runnable example workflows. Every run persists all materialized Artifacts as Markdown under its workflow bundle'sruns/<run-id>/artifacts/directory. Human Steps additionally persist private checkpoints under the ignored workspace.psi/fusion-flow/runs/directory; non-Human runs remain non-resumable.
Legacy handoff. An explicit
.flow.ts, Fuclaw, or@agent-flow/corerequest belongs to theflowskill underskills/fusion-flow-legacy/. Do not silently translate between the two runtimes.
When to Activate
Activate this skill when the user:
- Asks to run a G4 workflow they already have ("跑一下这个 / 帮我跑 / 执行"). This skill does not ship runnable demo examples; "run" always means a concrete workflow the user has.
- Asks to save, list, load, or reuse a workflow declaration.
- Mentions FusionFlow or agent-flow
- Describes any task that needs a multi-agent workflow or agent collaboration, even without saying "flow" — e.g. "让几个 agent 分别审一遍再汇总", "并行跑 N 个子任务再合并", "一步接一步处理(先 A 再 B 再 C)", "多角度评审后汇总", "把这件事拆成多个 agent 协作". If the task clearly benefits from orchestrating more than one agent / parallel branches / a multi-step pipeline, enter Authoring Mode (below) and offer to build a flow.
When in doubt about whether a task is "workflow-shaped": if it would take two or more coordinated LLM steps (fan-out/fan-in, an artifact pipeline, or per-item work), it qualifies — activate and propose a flow. A single one-shot question does not.
HARD RULE: when you recognize a multi-agent task, your job is to BUILD A FLOW — not to do it yourself
Once a task is workflow-shaped (multiple agents / parallel branches / multi-step pipeline / per-item work), your one default action is to enter Authoring Mode and build a G4 workflow. That is the entire point of this skill — the flow runtime spawns and coordinates the sub-agents; you do not play those sub-agents yourself.
Do NOT offer "我直接帮你做这一次" as an option, and especially do NOT make it the default. Building the flow IS how you help: doing it by hand throws away explicit dependencies, graph concurrency, named Artifacts, and the reusable G4 source.
❌ Real failure to never repeat (observed in testing): user said "让几个 AI 从安全/性能/可读性分别审一段代码再汇总". The agent replied with "方式 A:我直接帮你审这次代码 / 方式 B:给你做成可复用工作流" — offering to personally act as the three reviewers, with the manual path listed first as the default. Wrong. The correct response is to go straight into Authoring Mode and build the review flow: three reviewer Steps consume the same input, then one final Step consumes all three review artifacts. No A/B menu, no "I'll just review it myself".
✅ Correct shape: "🐾 这是个多 agent 协作任务,我来帮你搭一个工作流:3 个审查 agent(安全/性能/可读性)并行审 → 一个汇总 agent 合并成带严重等级的报告。" Then run the author loop (understand → model → author → static self-check → one heads-up line → run it once).
The only time you don't build a flow is when the user explicitly says they just want a one-off answer and not a tool ("别给我搭工具,就这一次,你直接说结论"). Even then, confirm — don't assume.
Do not activate this skill for .prose files — those belong to OpenProse.
Architecture
| Layer | Responsibility |
|---|---|
grammar/FusionFlow.g4 + parser |
G4 source to Core IR |
fusion_flow.workflow_graph |
immutable Step–Artifact structure and validation |
fusion_flow.workflow_runner |
Core IR to graph, plan, and checked dispatch |
fusion_flow.workflow_execution |
graph interpretation, dependencies, concurrency, timeouts, resources, and validated checkpoints |
fusion_flow.execution |
shared flow.* runtime; G4 Agent leaves reuse run/agent/session |
fusion_flow.job_store |
private, strict state-v3 Human wait/checkpoint state |
workspace run_flow / run_flow_resume tools |
file/JSON boundary, ephemeral Session-backed Agent/Program dispatch, and Human preparation/resume |
workspace clarify tool |
existing user-facing choice or free-text question formatter |
The Python runtime has one contract: execute_workflow requires inputs=;
Agent and Human callbacks receive (prompt, CompletionContext);
execute_plan requires a dispatch= callback with the exact
(StepNode, inputs, DispatchContext) signature. These are the supported forms,
not compatibility alternatives.
The skill's job is to:
- Turn the user's intent into valid Workflow G4 source, or resolve the concrete G4 workflow they pointed to.
- Save reusable source at the fixed path with existing file tools when requested.
- Start it through
run_flow. - If it reaches a Human Step, pass the nested
$fusion_flow/control.requestfields to the existingclarifytool, end the turn, and resume from the next user message. - Return only the final workflow output Artifact mapping.
Artifact Annotations
An Artifact declaration may have a free-form trailing comment. The runner reads
that comment as the Artifact's annotation and passes it to related Agent, Human,
and Program Steps. For Agent outputs, the same text is also used as the
submit_step_result property description.
const source_document: Artifact; -- Source content; suggested shape: an object with content, language, and metadata.
const summary_sections: Artifact; /* Ordered section objects with heading, body, and source references. */
The recommended unambiguous placement is a -- or /* ... */ comment
immediately after the declaration's semicolon on the same line. Comments that
cannot be associated with a declaration remain ordinary comments and never
cause an error. Everything inside an associated comment is ordinary text. No
@Artifact marker is required: @Artifact:, [object], field lists, JSON
examples, and any other notation are optional writing conventions, not syntax.
The runner does not parse a type or schema from them, and an unusual or
incomplete annotation never makes the workflow invalid.
Use annotations to explain meaning, suggested shape, important fields, ordering, units, provenance, and empty-value semantics. They provide context; they do not validate workflow inputs, Step results, checkpoints, foreach aggregates, or Program stdout. When a format must be enforced mechanically, use an explicit deterministic Program validation Step.
Intent Routing
Natural-language workflow requests map to these actions:
| What the user says (examples) | Action |
|---|---|
| "我能用这个干嘛 / 你能帮我做什么" | Describe capabilities in plain language (see "Capabilities" at the bottom) + offer to build a flow |
| "调用 daily-brief 的 workflow / 运行已保存的 daily-brief / reuse saved daily-brief" | Resolve flows/workflows/daily-brief/daily-brief.workflow, falling back to daily-brief.g4, collect its declared inputs, and start one fresh run with run_flow(flow_path=...). |
| "有哪些保存的工作流 / list workflows" | List the fixed flows/workflows/ directory with existing file tools. |
| "加载 X / 看看保存的 X" | Read the saved .workflow or .g4 file with existing file tools, preferring .workflow if both exist. |
| "把刚生成的这个保存为 X" | After self-check, save the self-contained bundle at flows/workflows/<slug>/: one .workflow or .g4 source file plus every referenced instruction Markdown file, preserving relative paths. |
| "跑一下这个 / 帮我跑 X / 执行这个 workflow" | Start the concrete workspace G4 source with run_flow; return outputs, or handle its Human request with clarify. |
| "接着上次那个跑 / 只重跑改动的部分" | Use run_flow_resume only for the active Human request already returned in this conversation. Arbitrary cache/resume is unsupported; otherwise offer a fresh run. |
| "看看结果 / 刚才那个跑完了吗" | Use the result already returned. A Human wait is not completion; wait for the user's answer rather than polling. |
| "环境齐不齐 / 能不能跑 / 帮我检查下" | Confirm that the G4 source parses and that all Steps use supported Agent, Human, or Program executors. |
| "帮我写个工作流做 X / 帮我编排 / 我想让几个 agent ..." | Author a new G4 workflow from natural language. See "Authoring Mode" below. |
| Anything else workflow-shaped | Interpret intent against this table |
Running a Workflow
Use the workspace run_flow tool for Workflow G4 source. It validates the workflow and returns either the final output Artifacts or one persisted Human request under the reserved $fusion_flow/control key.
Saved workflow reuse
When the user asks to run a saved workflow by name, resolve only an existing
slug directory under flows/workflows/; never treat the name as an arbitrary
path. Prefer <slug>.workflow and fall back to <slug>.g4. If the name is
ambiguous or neither source exists, ask the user to choose an existing saved
workflow.
Read the declaration and inspect input_workflow(...) before execution.
Resolve every declared input from the conversation; if any value is missing,
ask for it and end the turn without calling run_flow. Do not guess values or
call once with the default empty input object merely to discover missing
inputs. Once all inputs are available, invoke run_flow exactly once with the
resolved flow_path and complete inputs_json. Use an empty input object only
when the declaration has no inputs. Every initial invocation is a fresh run;
only a returned active Human request may continue through run_flow_resume.
Fixed-path reuse
- Save: use the existing file-writing capability to write one declaration
at
flows/workflows/<slug>/<slug>.workfloworflows/workflows/<slug>/<slug>.g4. If it references companion instruction Markdown, copy those files into the same canonical bundle while preserving every relative path; never leave a saved declaration pointing back to its one-off directory. This is an upper-layer instruction, not a new save/list/load operator. A parent Session or Agent Step may save a self-contained bundle generated within its assigned hierarchy. Saving never executes it. - List/read: use existing directory and file tools.
- Execute: only the parent Session invokes
run_flow(flow_path=...).
G4-only boundary
Only author and run Workflow G4 source. If the user points to any non-G4 workflow file, do not execute it, treat it as supported, or translate it implicitly. State that this skill accepts G4 source only. If the user explicitly asks to migrate that workflow, enter Authoring Mode and author one new G4 workflow from its intent.
Use a workspace-relative .workflow or .g4 path under flows/. Never guess, scan for, or execute a path outside the workspace.
One runnable file must contain exactly one workflow ... {} block and use
supported Agent, Human, or Program executors.
Pass named workflow inputs through inputs_json. Do not rewrite the G4 source just to inject one run's values.
Pass run-local resource pools through resource_capacities_json only when the workflow declares resource_requirement.
Call run_flow once. If it returns output Artifacts, use them as the result. If it returns a $fusion_flow/control object with status == "waiting_for_human", follow the Human protocol below. This reserved key cannot be a G4 Artifact ID, so an ordinary output Artifact named status is never control state.
Human wait and resume
run_flow_resume is only for a pending Human request; it is not a general cache or arbitrary-step resume API.
When run_flow or run_flow_resume returns a sole top-level $fusion_flow/control object whose status == "waiting_for_human":
- Call the existing
clarifytool with$fusion_flow/control.request.question,.options,.recommended, and.default. - Show the formatted text verbatim and END THE TURN. Do not call another tool and do not treat the question as an output Artifact.
- On the next user message, map a numbered choice to its option label. If the user selected the generated
Otherline without supplying text, ask for that text first. For an open-ended request with a non-emptydefault, map an affirmative acceptance such as “可以” or “ok” to that exact default. Preserve other free text or structured content. - For a single-output Human Step, JSON-encode every mapped option label or default as a JSON string. Pass other ordinary non-empty free text directly, except JSON-encode it as a JSON string when its trimmed spelling is valid JSON, starts with
{,[, or", or equalsNaN,Infinity, or-Infinity. JSON-encode non-string structured content. Multiple output Artifacts require a JSON object keyed exactly by those Artifact IDs; JSON-encode that object without dropping or adding keys. - Call
run_flow_resumewith the exact$fusion_flow/control.run_idand.request.request_id. - If another Human request is returned, repeat this protocol. Otherwise report the final output Artifact mapping.
Never invent, reuse, or guess a run/request ID. A changed workflow source, stale request, or conflicting duplicate response is a stop-and-report error.
Agent-, Human-, and Program-backed execution
Before executing a G4 workflow:
- Ensure every Step executor is declared as exactly one of
Agent,Human, orProgram. Every Program must declare an explicit workspace-relativeprogram_path. - Internally estimate cost and latency from the number of Agent and Program Steps. Fold that into one plain-language heads-up line.
- Say the heads-up line, then run without adding another approval gate unless the user explicitly said "只生成别跑".
Running is the runtime's job, not yours
Resolve the workspace-relative G4 path, submit it to run_flow, and report the returned output mapping. Do not reproduce parsing, dependency scheduling, resource leasing, or Step execution in the parent Session.
Agent-backed Steps must never invoke run_flow or start another workflow. A
Step may save a self-contained child declaration to the fixed reusable folder;
the parent Session remains the only launcher. Relative paths passed by a Step
to read, write, or edit resolve against the invoking psi workspace root,
independent of the launcher process working directory.
Staged execution
Workflows without Human Steps finish in the initial run_flow call. A Human workflow executes to the next Human frontier, persists a checkpoint, releases the current Session turn, and continues only through run_flow_resume. Do not call the legacy .flow.ts flow_run(start/status/result) tool for G4 source, and do not invent polling, PIDs, workers, or a separate approval inbox.
Checkpoint integrity and resume safety
An ExecutionCheckpoint is valid only for its exact non-empty workflow_id and plan_digest. The digest is SHA-256 over a canonical serialization of the current graph semantics and explicit execution-plan fibers; matching Step and Artifact IDs from another workflow or graph version are not enough. Values must be strict, finite JSON values, and resume compares them recursively with type identity, so JSON true never matches JSON 1. The executor also validates unique known operation IDs, dependency closure, and the exact set of materialized values before it skips any work.
The public run_flow_resume boundary additionally validates the current workflow definition against the definition_digest recorded when the run was created; that definition includes the .workflow or .g4 source and every referenced Markdown instruction. Persisted Human runs use the strict state-v3 schema; state-v2 and all other older versions are rejected rather than resumed through a compatibility path. Each resume is protected by an OS-released advisory file lock plus an in-process reservation guard; a leftover lock file is not ownership, and an abrupt process exit releases the live advisory lease. Do not copy checkpoints between workflows, edit persisted state, or bypass the matching run_id / request_id protocol.
When a run fails
A compilation or Step exception is a STOP-and-report point. Report the failing Step or diagnostic exposed by run_flow, state one best hypothesis, and hand back to the user.
These actions are forbidden when a run fails:
- editing the workflow or creating a modified copy to work around the failure;
- bypassing
run_flowand manually executing individual Steps; - silently retrying or approximating an unsupported operator or executor.
Do not create a mock or offline twin with baked-in output.
Don't fake or guess progress
The tool does not expose intermediate progress. Do not invent node status while the call is in flight.
Reading a Run
When a call returns output Artifacts, summarize them. The runtime has already
persisted every materialized input, intermediate, selected, and final Artifact
as one Markdown file under the workflow bundle's
runs/<run-id>/artifacts/ directory. String values are written verbatim;
non-string strict JSON values use a fenced json block. These user-visible
files are separate from the private Human checkpoint. When a call returns a
Human request, ask it through clarify; the request text is control state, not
an Artifact or completed result.
File Locations
Paths are relative to the workspace:
| File | Location | Purpose |
|---|---|---|
flows/<task-slug>/ |
one-off authored Workflow G4 source | |
flows/<task-slug>/instructions/*.md |
optional long-form instructions for that one-off source | |
flows/workflows/<slug>/<slug>.workflow or <slug>.g4 |
reusable G4 source (.workflow preferred when both exist) |
|
flows/workflows/<slug>/instructions/*.md |
optional long-form instructions for that reusable source | |
<workflow-bundle>/runs/<run-id>/artifacts/*.md |
one Markdown file for every materialized Artifact in one run | |
.psi/fusion-flow/runs/<run-id>.json |
private resumable state for workflows containing Human Steps |
Authoring Mode
This is the flagship: turn a natural-language intent into a runnable G4 workflow. The user normally describes what they want in plain words ("帮我写个工作流做 X"). A request to run an already-saved workflow by name is reuse, not an authoring request.
NO-MOCK RULE (global, applies to all of Authoring Mode). When you build a flow for the user, author exactly one real G4 workflow and NEVER fabricate a mock/offline/simplified twin to "test" or "demonstrate" it. A twin with hardcoded sample output, fake numbers, or a fake executor standing in for the real work is a forgery — it always "passes" regardless of what the real flow does, so it proves nothing and misleads the user. Validate the one real workflow, then actually run it. If the user explicitly later asks for an offline twin, that's a separate request you confirm first — never self-initiate one.
Inlined source snippets in this Skill are authoring guidance, not runnable bundled workflows. The ban is on fabricating a second version of the user's flow.
When to enter Authoring Mode
- User describes a workflow they want built: "帮我写个工作流 ..." / "make a flow that ..." / "帮我编排 ..." / similar.
- User asks "帮我写一个 flow ..." / "make a flow that ..." / similar in any LLM client.
- User edits existing Workflow G4 source and asks you to "rewrite" or "扩展".
- User describes a workflow-shaped task without naming "flow" — anything needing two or more coordinated agents / parallel branches / a multi-step pipeline / per-item work (see "When to Activate"). In that case, don't wait for the word "flow": offer to build one, then run the author loop below.
Planning contract
Before writing Workflow G4 source, make an internal planning contract for the requested workflow. It must identify:
- the user's intent and concrete success condition;
- every external input and final output Artifact;
- each Step's single responsibility and its consumed and produced Artifacts;
- information dependencies and the owner of every material constraint;
- concurrency, timeout, retry, resource, and user-stated cost limits.
Assign mechanically decidable constraints to graph structure or a deterministic Program Step. Assign constraints that require judgment to an Agent Step whose instruction names that responsibility. Let dependencies determine execution: fan out independent work, keep dependent work sequential, and join branches only when a consumer needs all of their results. Keep this contract in the authoring context; do not expose framework planning detail to a non-technical user.
The 5-step author loop
- Understand intent — restate the user's goal in 1 sentence. If genuinely ambiguous, ask one clarifying question (don't grill them). Note whether the user looks like a developer (asked to edit Workflow G4 source or mentioned operators) — that's the only case where you show technical detail later. Everyone else gets the minimal plain-language summary.
- Model the workflow — complete the planning contract and match the intent to one of the executable reference patterns below. Let information dependencies determine graph depth: add an intermediate aggregation layer only when downstream work needs a coherent result from a distinct group of upstream Artifacts.
- Author one Workflow G4 source — before writing, read
grammar/FusionFlow.g4completely and treat it as the sole source of truth for FusionFlow syntax and preset operators. Use only declarations, assertions, terms, and operators documented there. Use the workspace-provided target path; never invent a second copy. - Static self-check — compare the source against
grammar/FusionFlow.g4and the executable guardrails in this Skill.run_flowrepeats this with its built-incheck_workflowpass before dispatch; there is no separate validation tool or CLI. - Start it once — the user asked you to do a task, not to receive an implementation artifact. After the static self-check, say ONE friendly heads-up line ("🚀 方案定了,正在帮你跑,预计几分钟…" — a notice, NOT a question), then call
run_flowonce. A declared Human Step may later ask its own task-specific question through the Human protocol; that is part of execution, not an extra pre-run gate. Do NOT ask "要不要跑 / 跑不跑" and do NOT wait for跑. The only exception is when the user explicitly says "只生成别跑 / 先给我看看别执行".
Never mention the source file, its path, G4, operator names, static-check stages, or internal runnable artifacts to a non-technical user. From their side you are just doing the task they asked for. If they ask "你在干嘛 / 怎么做的", answer in plain business language ("我让几个分析分头跑、再汇总").
Talking to the user while you work
Before calling run_flow, send one short heads-up such as "🚀 方案定了,正在帮你跑,预计几分钟…". The tools expose no node-level progress, so do not claim that an individual Step or branch has started or completed. When a call returns final outputs, lead with the result; when it returns a Human request, follow the Human protocol. Do not add an approval question between authoring and execution.
Hard stops in Authoring Mode (real TUI failures, do not repeat)
These are not style preferences. Each one was observed corrupting a real author run. These bans apply whether you're mid-author or already running:
- Don't fake a result instead of running. The user wants the real outcome. After the static self-check you call
run_flowonce (see step 5) — you do not stop and hand back a file, and you never substitute a made-up answer for an actual run. - Write OR run any extra workflow source beyond the one
.workflowor.g4file the task needs — not an offline twin, not a "simpler version", not a "v2", not a "test harness". Companion instruction Markdown belongs to the same bundle and is not another workflow source. An offline twin with baked-in output is a forgery, not a test. If the user later wants one, that is a separate explicit request. - Report numbers you did not get from a real run — never present mock data, sample data, or figures from an unrelated file as if they are this flow's result. The only result you report is what the
run_flowcall actually returned. If it fails, report the failure instead of papering over it with invented numbers. - Write outside the workspace-managed
flows/location — do not scan the filesystem for another flow project or create a sibling bundle copy. If the intended path is ambiguous, ask the user instead of guessing. - Start another workflow from inside an Agent Step — nested
run_flowcalls are forbidden. A Step may save a self-contained child declaration, but only the parent Session may launch it.
The real run is how you deliver — there is no "spend-free preview" step to offer the user. Perform the static self-check, then call run_flow once.
Heads-up line (说一句就开跑,不是 gate)
Keep this minimal. A real investor ("悠悠") and an internal teammate ("张浩") both bailed on the authoring flow because the summary was wall-to-wall framework jargon (parallel / pmap / reduce / evaluate / choice / 原语 / 异构复合工作流). Their words: "这么专业应该不是给我这种用户用的吧" / "这表述太专业太多专有名词了,我都不知道咋聊了". This line is a 告知, not a go/no-go gate — you say it and then immediately run. It exists so the user isn't surprised by a few minutes' wait / the cost, NOT to ask permission.
Default heads-up (use this for everyone unless they're clearly a developer): one plain-language sentence on what they'll get + a rough time estimate. No primitive names, no API names, no pattern names, no file path, no per-step breakdown, no token math, no "要不要跑".
🚀 我来帮你做:<一句话讲清楚要产出什么,e.g. "并行调研 5 个 AI 方向,汇总打分后给你一份带『重点关注 / 投资机会』的总报告">,预计几分钟,这就开始。
That's it — one line, then you run. Do not add 做什么 / 要多久 / 你会拿到 as separate fields, do not list steps, do not show 🔧/🎯/📝 lines, do not show the file path, do not ask for approval. If the user is clearly a developer (asked to edit Workflow G4 source, mentioned operators, or explicitly asks "用了哪些语法 / 给我看结构 / 文件在哪"), you may then show technical detail on demand:
🔧 3 个审查 Step 共用输入,1 个汇总 Step 消费三个结果 | `max_concurrency = 3`
Only show that line when a developer explicitly asks for it. Never push it at a business user, and never volunteer the file path unprompted.
Jargon → plain-language map (so the default sentence stays clean). Never say the left; say the right:
| 框架黑话(别说) | 业务语言(要这么说) |
|---|---|
| G4 / operator | 工作流结构 |
| Step | 一次处理 |
| Artifact | 中间结果 |
max_concurrency |
同时处理 |
consumes(step) == [result_a, result_b] |
汇总多个结果 |
| 异构复合工作流 | 多方向 + 分层汇总 |
| token / LLM 调用 | (折成)几分钟 / 花多少钱 |
Token estimate rule of thumb: each ordinary LLM work step ≈ 1500 input + 800 output tokens; each structured judgement step ≈ 2000 input + 50 output. Sum, then convert to RMB at the provider's listed rate (火山 ARK Agent Plan 包月里这是 0 元,flag it as "≈ 0 (Agent Plan)").
Reference patterns
Read grammar/FusionFlow.g4 completely before using these patterns. The grammar is authoritative; these patterns illustrate artifact dependencies and do not add syntax or operators.
| Pattern | Workflow shape | When to use |
|---|---|---|
| Fan-out + fan-in | Several Steps each use consumes(step) == [shared_artifact]; one final Step uses consumes(final_step) == [result_a, result_b]. Set max_concurrency on the workflow when needed. |
PR review, multi-perspective audit, content moderation. |
| Artifact pipeline | Each Step produces the Artifact consumed by the next Step. Use max_attempts only when rerunning that individual Step is safe. |
Writing, ETL, and refine-and-check work. |
| Per-item map | Bind one List-valued source Artifact with foreach_item; use workflow max_concurrency or resources when a limit is needed. |
Parallel processing with ordered results; ordinary failures are raised together after siblings finish. |
| Named Artifact selection | Keep every candidate result explicit, then bind selected_artifact == if(formula, artifact_a, artifact_b) and use selected_artifact in ordinary dataflow. For priority selection, chain named intermediate Artifacts. |
Eagerly run all candidate producers, then choose one value for downstream Steps. |
| Declarative feedback | Declare a seeded state as an input_workflow Artifact, consume it in the region, and let one Step produce that same Artifact as state[n+1]. End the region with one TerminalStep whose only result is a strict BoolArtifact. |
Iterative engineering or agent state transitions with synchronous snapshot reads and final-state publication. |
| Composite workflow | Combine artifact chains, fan-out/fan-in, explicit bounded Agent Steps, and named Artifact selections. | When one simple pattern does not cover the task. |
Before reporting a missing capability for a conditional request, first check whether eager value selection is sufficient. Named Artifact selection runs every candidate producer and only selects the value passed downstream. If the request requires lazy branch activation or guarantees that an unselected producer will not run, report that limitation instead of emitting an approximation. Never invent a keyword or operator to make the source look complete.
Full-featured in-context example
This is the canonical review shape from the activation example: three independent review Steps consume the same source, then one final Step consumes their outputs.
-- SCENARIO: security, performance, and readability review followed by one report
const source_code: Artifact;
const security_findings: Artifact;
const performance_findings: Artifact;
const readability_findings: Artifact;
const final_report: Artifact;
const security_review: Step;
const performance_review: Step;
const readability_review: Step;
const synthesize_report: Step;
const security_agent: Agent, Executor;
const performance_agent: Agent, Executor;
const readability_agent: Agent, Executor;
const editor_agent: Agent, Executor;
workflow code_review {
-- DATA FLOW
input_workflow(code_review) == [source_code];
consumes(security_review) == [source_code];
produces(security_review) == [security_findings];
consumes(performance_review) == [source_code];
produces(performance_review) == [performance_findings];
consumes(readability_review) == [source_code];
produces(readability_review) == [readability_findings];
consumes(synthesize_report) ==
[security_findings, performance_findings, readability_findings];
produces(synthesize_report) == [final_report];
output_workflow(code_review) == [final_report];
-- EXECUTOR ASSIGNMENT
step_executor(security_review) == security_agent;
step_executor(performance_review) == performance_agent;
step_executor(readability_review) == readability_agent;
step_executor(synthesize_report) == editor_agent;
-- STEP CONFIGURATION
step_name(security_review) == "Security Review";
step_instruction(security_review) == "Inspect the source for exploitable behavior and unsafe trust boundaries. Return prioritized findings with concrete evidence and remediation.";
step_timeout(security_review) == 300;
step_name(performance_review) == "Performance Review";
step_instruction(performance_review) == "Identify material performance risks in the source. Explain the triggering workload, likely impact, evidence, and practical fixes.";
step_timeout(performance_review) == 300;
step_name(readability_review) == "Readability Review";
step_instruction(readability_review) == "Review maintainability and clarity. Return specific high-impact issues, why they matter, and focused improvements.";
step_timeout(readability_review) == 300;
step_name(synthesize_report) == "Synthesize Report";
step_instruction(synthesize_report) == "Combine the three reviews into one deduplicated report. Preserve evidence, resolve conflicts explicitly, prioritize actions, and separate findings from inference.";
-- WORKFLOW CONFIGURATION
max_concurrency(code_review) == 3;
workflow_timeout(code_review) == 900;
}
G4 source of truth
Before authoring, read grammar/FusionFlow.g4 completely. It is the sole authority for surface syntax, declarations, assertions, formulas, terms, and preset operator signatures. This skill additionally defines which grammar-valid shapes the executable graph backend accepts.
Runner-specific typed catalog extensions use the grammar's generic operator-call syntax without changing its preset catalog. In particular, depends_on(Step, Step) -> Bool is registered by fusion_flow/workflow_runner.py and is executable there, but is not one of the grammar's 21 canonical preset operators.
Executable graph backend guardrails
- Every dataflow operator has one owner and an explicit Artifact List RHS.
- Every executable
ifhas the top-level shapeselected_artifact == if(condition, artifact_a, artifact_b);. Never putifinside a dataflow List or anotherif; chain named intermediate Artifacts instead. - Selection is eager: every candidate producer runs before the selected value is published.
- A Step instruction is either short JSON-style quoted text or a
"./..."UTF-8 text-file path relative to the.workflowor.g4source file. Use a companion Markdown file when the instruction needs multiple sections.
Modeling rules
- Group assertions by concern in this exact order:
DATA FLOW,EXECUTOR ASSIGNMENT,STEP CONFIGURATION,SCHEDULING CONFIGURATION,WORKFLOW CONFIGURATION. Omit empty groups. - In
DATA FLOW, declare the complete external input List once, then every Step'sconsumes/producesedges and named Artifact selections in dependency order, then the complete external output List once. - Use exactly one symmetric Artifact dataflow contract:
input_workflow(workflow) == [artifact_a, artifact_b];,consumes(step) == [artifact_a, artifact_b];,produces(step) == [artifact_a, artifact_b];, andoutput_workflow(workflow) == [artifact_a, artifact_b];. All four operators returnList; even one Artifact requires an explicit List literal such as[artifact]. Never use these calls as standalone assertions, with== True, with an Artifact as a second argument, or through alternate multi variants. - Bool shorthand is only for supported non-dataflow Bool operators such as
independent(step)anddepends_on(step, predecessor). Keep== Falseexplicit. Retain the right-hand value for every non-Bool operator. - Write each Step display name directly as a JSON string, for example
step_name(security_review) == "Security Review";. Do not declare an intermediateStepNameconstant or emit a symbolic display name ending in_name; symbolic StepName values are rejected before compilation. - When the user supplies a grammar-valid literal as a typed constant name, including a restricted quoted ID or
"./..."path, preserve that literal and use it directly as the required preset value; do not hide it behind an alias constant and an extra equality. - Write every
step_instructionas an executable task specification, not a label. State the objective, how to interpret consumed Artifacts, important constraints or evidence requirements, and the expected result. A name such as"task_name"is not an instruction. - Keep each Step independently understandable and bounded. Let information dependencies determine the hierarchy: synthesize a distinct group of upstream Artifacts before combining it with other groups only when that intermediate result is genuinely consumed downstream. Do not add layers merely because a request is large, and do not collapse separable work into coarse Steps merely to minimize node count.
- Model data sequencing through Artifact edges: a Step that produces an Artifact precedes a Step that consumes it. When ordering is required without passing data, use
depends_on(step, predecessor) == True; repeat it for multiple predecessors. Declaration order never defines execution order. - Preserve the external data boundary from the user's intent. Fan-out Steps that analyze the same subject reuse one shared input Artifact; do not split it into synthetic per-branch workflow inputs.
- Emit every explicitly requested relation. Every operand must be a declared grammar term:
_and...are not wildcards. Declare typed constants for required operands, or omit an optional configuration instead of inserting placeholders. - Model fan-out by making several steps consume the same artifact.
- Model fan-in with
consumes(step) == [artifact_a, artifact_b];. - Use
foreach_item(step, source_artifact) == item_bindingwhen a source Artifact contains a finite JSON List. The item binding is local to the expanded Step and is added to that iteration's inputs; do not also declare it as a workflow input. - Foreach iterations run in parallel by default. Only workflow
max_concurrencyand resource capacity bound them; there is no per-foreach limit. - Normal foreach outputs become source-ordered Lists only after every iteration succeeds; an empty source produces empty Lists. Iteration failures are raised, never declared or returned as G4 Artifacts.
- Bind each step to its executor with
step_executor. - Configure concurrency, timeouts, retries, and resources with the corresponding supported operators. Resources,
step_timeout,max_attempts, and checkpoint progress apply independently to each foreach iteration. - Treat
independent(step)only as a hint. Artifact dependencies anddepends_onstill decide when the Step is ready. - Declare resource demand with
resource_requirement(step, resource). Resource capacities or concrete IDs come from runner configuration, never from.workflowsource. - Agent- and Program-backed foreach Steps are executable. Human-backed foreach is rejected before dispatch until Human requests and responses carry iteration identity.
- A Program failure inside foreach participates in that Step's
max_attemptsand then joins the aggregate exception. Outside foreach, preserve the existing$fusion_flow/program_errorerror-valued Artifact behavior. - Ordinary terminal foreach failures do not cancel siblings; after all ordinary iterations finish, the runner raises them together. Successful iteration checkpoints are reused on resume. Cancellation, workflow timeout, Human suspension, and graph/checkpoint/allocator invariant failures still escape immediately.
- Unknown or unsupported assertions remain residual and stop execution. Never delete them, comment them out, or bypass residual validation to make a run start.
- Lower executable
ifas a named Artifact selection:selected_artifact == if(formula, artifact_a, artifact_b);, followed by ordinary list dataflow such asconsumes(final_step) == [selected_artifact];. - Variables, quantifiers, rules, implications, biconditionals, query/SAT/optimization requests, local concept declarations, local operator declarations, and imperative blocks are outside this language.
- Never emit imports, imperative runtime calls,
run(...), or inventedparallel/pipeline/forblocks.
Foreach example
const enrich_batch: Workflow;
const enrich_item: Step;
const worker: Agent, Executor;
const items: Artifact;
const item: Artifact;
const enriched_items: Artifact;
workflow enrich_batch {
-- DATA FLOW
input_workflow(enrich_batch) == [items];
foreach_item(enrich_item, items) == item;
produces(enrich_item) == [enriched_items];
output_workflow(enrich_batch) == [enriched_items];
-- EXECUTOR ASSIGNMENT
step_executor(enrich_item) == worker;
-- STEP CONFIGURATION
step_name(enrich_item) == "Enrich Item";
step_instruction(enrich_item) == "Enrich the local item input and return the enriched_items value.";
step_timeout(enrich_item) == 120;
max_attempts(enrich_item) == 2;
-- WORKFLOW CONFIGURATION
max_concurrency(enrich_batch) == 8;
}
At runtime items must be a JSON List. Iterations run in parallel and
enriched_items preserves source order. If ordinary iterations fail, siblings
finish and the failures are raised together; successful iteration checkpoints
can be reused on resume.
Executor configuration
Declare every executor as exactly one of Agent, Executor, Human, Executor, or Program, Executor, bind it with step_executor, and give each Step a step_instruction.
Agent configuration may use agent_config, agent_system_prompt,
allowed_tool, max_output_tokens, temperature, reasoning_effort, and
max_turns. The declared system prompt augments the fixed Step safety/output
protocol; it cannot replace it. allowed_tool narrows the host-safe tool
registry and cannot re-enable a denied workflow launcher. The current workspace
AI socket fixes provider routing, so a non-default model, engine, or
api_base is rejected explicitly instead of being ignored.
Agent-backed Steps execute through the shared flow.agent() and
flow.session() primitives inside fusion_flow.execution.run(). Their
completion callback must return a mapping keyed exactly by the declared output
Artifact IDs. A normally completed Agent turn may return either one strict JSON
object or one standalone json fence. Malformed JSON is returned to the model
for output-only correction without rerunning the Step. If the third ordinary
text response is still invalid, the runtime may remove only unambiguous trailing
commas by trying json-repair once. The repaired result is accepted only when it
is canonically identical, including JSON value types, to a string-aware pass that
removes trailing commas and nothing else; strict parsing and exact-key validation
then run again. Every other malformed result fails without publishing any
Artifact, regardless of output cardinality; invalid raw text is never bound or
broadcast.
A Human Step may request an approval, choose among up to four options, or accept open-ended/structured input. Its dedicated preparation Agent receives the resolved instruction text, consumed Artifacts, and output contract, then emits the arguments for the existing clarify tool. It never asks the user itself, and its question text never becomes a produced Artifact. The next user response becomes the Human Step result after run_flow_resume. Multiple output Artifacts require a JSON object keyed exactly by those Artifact IDs; a zero-output Human Step acts as a pure gate.
Every Program must declare one explicit workspace-relative script or source path:
const worker: Program, Executor;
program_path(worker) == "./bin/worker";
The public workspace runner has no catalog path resolver, so do not use a bare Path identity. program_path names one workspace-local regular file, not a shell command: do not append arguments, operators, pipes, or environment assignments. It does not need an executable bit, a shebang, or chmod. A specialized Program Agent may inspect the workspace, prepare or install the required language runtime, dependencies, compiler, or toolchain, and interpret or compile the declared file. The runtime supplies one newline-terminated JSON object as the authoritative stdin:
{
"instruction": "<resolved step_instruction text>",
"inputs": {
"<consumed Artifact ID>": "<runtime value>"
}
}
Fidelity-mode interpreted execution does not accept an arbitrary argv from the Program Agent. The Agent selects one interpreter executable, and the host constructs exactly [interpreter, declared_script, *logical_argv[1:]]; do not add interpreter flags, inline code, another script, extra arguments, or reorder/drop the declared logical arguments. Compiled languages must use structured compile_program, which binds the compiler argv, declared source hash, artifact hashes, and one exact launch argv. execute_program may launch that compiled argv only after the host revalidates the registered source and artifacts. Preparation shells must not substitute for either structured operation.
The structured tools capture the actual argv, stdout and stderr bytes, exit code, and launch error separately. Once the real Program launches in fidelity mode, it is the sole attempt: never call execute_program again, even after a nonzero exit, invalid-input/domain error, or invalid output. Preserve that first result or error and let submit_program_result commit it deterministically; the model never authors the Artifact values itself. Before launch, the Program Agent may install missing environment or toolchain components and retry preparation failures, but it must not patch/replace the declared script, alter consumed input Artifact values or stdin, or reinterpret output. Only include the following exact standalone line in the resolved step_instruction when the user deliberately authorizes successful completion to outrank fidelity:
Program execution policy: successful completion outranks fidelity.
No paraphrase enables adaptation. An authorized script or stdin adaptation must state a concrete adaptation_reason, and the consumed input Artifact values remain immutable.
For one produced Artifact, valid UTF-8 stdout is that Artifact's exact string value, including trailing newlines. For multiple produced Artifacts, stdout must be exactly one strict, finite JSON object keyed by all and only those Artifact IDs; NaN, Infinity, numeric overflow to infinity, nested non-finite values, and duplicate object keys are rejected. A Program that produces no Artifacts must not write stdout. Launch errors, nonzero exits, invalid UTF-8, and output-format errors become the same {"$fusion_flow/program_error": {...}} value on every declared output Artifact, preserving captured attempts; a failing zero-output Program raises because it has no Artifact for the diagnostic. Never reinterpret an error-valued Artifact as success.
execute_program runs without a shell in a separate POSIX process group or Windows Job Object. Shielded cleanup terminates members of that boundary on failure, declared Step/workflow timeout, cancellation, output overflow, and after a direct child exits with managed descendants still present. There is no internal 300-second Program timeout. Stdout and stderr are streamed with retained-output defaults of 4 MiB and 1 MiB respectively; set PSI_FUSION_FLOW_PROGRAM_STDOUT_LIMIT_BYTES or PSI_FUSION_FLOW_PROGRAM_STDERR_LIMIT_BYTES to a positive integer to override them. Exceeding either limit terminates the process boundary. Environment preparation can use shell tools, so this remains a trusted-workspace lifecycle boundary rather than a host sandbox; on POSIX, code that deliberately creates a new session/process group leaves the managed group.
Named Artifact selection with if
Keep every candidate result explicit and produced by a Step. Bind each if result to a declared Artifact before downstream dataflow:
const incoming_case: Artifact;
const primary_criterion: Artifact;
const block_criterion: Artifact;
const review_criterion: Artifact;
const exception_criterion: Artifact;
const primary_observation: Artifact;
const block_observation: Artifact;
const review_observation: Artifact;
const exception_observation: Artifact;
const primary_result: Artifact;
const review_result: Artifact;
const fallback_result: Artifact;
const review_or_fallback: Artifact;
const selected_result: Artifact;
const final_result: Artifact;
const triage_step: Step;
const primary_handler_step: Step;
const review_handler_step: Step;
const fallback_handler_step: Step;
const final_step: Step;
const triage_agent: Agent, Executor;
const primary_handler: Agent, Executor;
const review_handler: Agent, Executor;
const fallback_handler: Agent, Executor;
const final_consumer: Agent, Executor;
workflow priority_routing {
-- DATA FLOW
input_workflow(priority_routing) ==
[incoming_case, primary_criterion, block_criterion, review_criterion, exception_criterion];
consumes(triage_step) == [incoming_case];
produces(triage_step) ==
[primary_observation, block_observation, review_observation, exception_observation];
consumes(primary_handler_step) == [incoming_case];
produces(primary_handler_step) == [primary_result];
consumes(review_handler_step) == [incoming_case];
produces(review_handler_step) == [review_result];
consumes(fallback_handler_step) == [incoming_case];
produces(fallback_handler_step) == [fallback_result];
review_or_fallback == if(
(review_observation = review_criterion) OR (exception_observation = exception_criterion),
review_result,
fallback_result
);
selected_result == if(
(primary_observation = primary_criterion) AND !(block_observation = block_criterion),
primary_result,
review_or_fallback
);
consumes(final_step) == [selected_result];
produces(final_step) == [final_result];
output_workflow(priority_routing) == [final_result];
-- EXECUTOR ASSIGNMENT
step_executor(triage_step) == triage_agent;
step_executor(primary_handler_step) == primary_handler;
step_executor(review_handler_step) == review_handler;
step_executor(fallback_handler_step) == fallback_handler;
step_executor(final_step) == final_consumer;
-- STEP CONFIGURATION
step_name(triage_step) == "Triage";
step_instruction(triage_step) == "Evaluate incoming_case against each supplied criterion. Produce one observation Artifact per criterion, citing the relevant evidence and marking uncertainty.";
step_name(primary_handler_step) == "Primary Handler";
step_instruction(primary_handler_step) == "Produce the primary handling result for incoming_case. Explain the decision, preserve material constraints, and return a result suitable for downstream selection.";
step_name(review_handler_step) == "Review Handler";
step_instruction(review_handler_step) == "Produce a reviewed handling result for incoming_case. Identify risks or ambiguities, resolve what the available evidence supports, and state any remaining uncertainty.";
step_name(fallback_handler_step) == "Fallback Handler";
step_instruction(fallback_handler_step) == "Produce a safe fallback result for incoming_case when stronger handling criteria are not met. Explain limitations and preserve enough context for finalization.";
step_name(final_step) == "Finalize Result";
step_instruction(final_step) == "Turn the selected_result into the final response. Preserve its supported conclusions, remove routing metadata, and make unresolved uncertainty explicit.";
}
- Build conditions with
=,!=,<,<=,>, or>=; reserve==for the surrounding assertion. - Combine comparisons with
!,AND, andOR. - Both branches must be declared Artifacts. The selection result must also be a declared Artifact.
- Every candidate producer runs. Selection is eager value routing, not lazy control flow.
- For more choices, chain named intermediate Artifacts in priority order; do not nest an
ifdirectly inside anotherif. - Never place
if(...)inline insideinput_workflow,consumes,produces, oroutput_workflow; those operators still take explicit Artifact Lists. - Do not replace candidate Artifacts with Boolean Step payloads or invent
switch,choice, or conditional blocks.
Use free-form quoted text only where the typed catalog expects an Instruction or StepName. Do not encode shell commands, code, large source documents, or secrets as instruction text. Put a long instruction in a companion Markdown file; pass source material through input Artifacts.
Anti-patterns to refuse
- Hand-writing imports or imperative runtime calls. The authored program is Workflow G4 source.
- Inventing a keyword or operator. Flexible call syntax does not make unknown names valid.
- Using
==inside a condition or=for a workflow assertion. These have different grammar roles. - Using a symbolic instruction label as the task. A Step needs actionable instruction text or a companion instruction file, not only a name such as
"task_label". - Treating
max_attemptsas a workflow loop or score gate. It only sets the attempt limit for one Step. - Expanding a large item list without a cost check. Every explicit Agent Step may consume a model call; keep the bounded expansion intentional.
- Inlining a large source document as an instruction. Keep the task specification in the instruction and pass source material through an input Artifact.
- Relaying an external tool's secret through workflow source. Let the tool read its own configuration; never encode credentials in constants.
- Sharing mutable state between parallel branches. Use artifacts and explicit producer/consumer relations.
- Inventing
while,for,termination_signal, or a second feedback-state identity. The committed feedback state keeps one Artifact identity across epochs. A transientnext_stateproduced inside the epoch is valid only when one ordinary commit Step consumes it and remains the unique writer of the original feedback state. - Using a general Artifact or truthy value as loop control. A TerminalStep has exactly one
BoolArtifactoutput and must return the strict Booleantrueorfalse.
Declarative feedback rules
Feedback is a versioned dataflow interpretation, not imperative source syntax.
Within a valid region, consumes(step) == [state] reads state[n], while the
unique produces(writer) == [state] stages state[n+1]. All state readers use
the same snapshot, and all next-state writers commit together.
const state: Artifact;
const evidence: Artifact;
const done: BoolArtifact;
const improve: Step;
const terminal: TerminalStep;
input_workflow(iterative_work) == [state];
consumes(improve) == [state];
produces(improve) == [state, evidence];
consumes(terminal) == [evidence];
produces(terminal) == [done];
output_workflow(iterative_work) == [state];
The surrounding workflow still must provide normal Step metadata; the fragment
only shows the feedback and terminal contracts. The terminal produces line
can be omitted, in which case the compiler creates an internal Boolean output.
Do not write [] to mean omission. The explicit BoolArtifact is traceable loop
control only; do not consume it from another Step or list it in
output_workflow.
Author feedback only when every state has a workflow input seed and one next
writer, removing the feedback dependencies makes the epoch graph acyclic, and
one TerminalStep uniquely depends on the region. The runtime commits n+1
before acting on the predicate: false continues and true publishes that
just-committed state. Outside consumers never observe intermediate epochs.
Current execution is intentionally fail closed for multiple/nested feedback
regions, feedback combined with if selection or foreach, Human Steps inside
feedback, and any residual cycle. A host may supply max_loop_epochs as a
safety guard; do not invent an iteration-limit operator in source.
Use examples/loop_engineering.workflow and examples/react_loop.workflow as
the complete reference sources. The ReAct example follows the source loop
literally: reason produces thought and action, env_step produces
observation and business done, update writes the next prompt, and a
separate TerminalStep validates done as closed loop control.
Code template
Every authored workflow follows this shape:
-- SCENARIO: <one-line user-facing description>
-- AUTHORED: <YYYY-MM-DD HH:mm:ss> from intent: "<original user intent>"
const input_artifact: Artifact;
const output_artifact: Artifact;
const work_step: Step;
const worker: Agent, Executor;
workflow workflow_name {
-- DATA FLOW
input_workflow(workflow_name) == [input_artifact];
consumes(work_step) == [input_artifact];
produces(work_step) == [output_artifact];
output_workflow(workflow_name) == [output_artifact];
-- EXECUTOR ASSIGNMENT
step_executor(work_step) == worker;
-- STEP CONFIGURATION
step_name(work_step) == "Work";
step_instruction(work_step) == "Complete the requested transformation using input_artifact, follow the user's stated constraints, and return the concrete result as output_artifact.";
}
Extend this skeleton only with syntax and preset operators documented in grammar/FusionFlow.g4.
Static self-check
Before the initial run_flow call, inspect the source in order:
- graph values may be untyped; when explicitly typed, their concepts include
Artifact; - every other identity is declared with a supported concept;
- assertions use
==, while formulas use comparison operators; - each operator uses the documented arity and supported shape;
- each Step has a supported Agent, Human, or Program executor, name, instruction, and explicit data/control dependencies;
- the planning contract covers intent, success, interfaces, responsibilities, constraint ownership, dependencies, and operational limits;
- no residual or unsupported operator is emitted.
This manual source review is not a second tool or CLI invocation. Inside run_flow, check_workflow requires exactly one workflow, delegates graph semantics to WorkflowGraphCompiler, rejects unsupported residual assertions and graph values with explicit concepts that omit Artifact, requires every Step instruction and Program path, and rejects untyped or ambiguous executor declarations. Parsing, checking, and compilation all occur before dispatch.
Running it (automatic, right after the self-check)
- Call
run_flow(flow_path=..., inputs_json=..., resource_capacities_json=...)once. Omit resource capacities when the graph declares no resource requirement. - If it returns a
$fusion_flow/controlHuman-wait envelope, follow the Human wait/resume protocol exactly. Do not present that envelope as the workflow result. - When a call returns output Artifacts, summarize them in plain language.
- On error, report the compiler diagnostic or failed Step without creating a second workflow or bypassing the runner.
What Authoring Mode is NOT
- It is not a guarantee the workflow gets good content. We control structure and execution; the task instructions still depend on the user's domain.
- It is not auto-iterating on content. The user reads the result and asks for changes, but there is no "要不要跑" gate before the first run.
- It is not a reason to show implementation details to a business user. Technical users can ask for the Workflow G4 source and structure on demand.
Doctor Checks
When the user asks whether a workflow can run:
- Confirm the source is a readable workspace-relative
.workflowor.g4file. - Perform the static self-check above. The same checks run inside
run_flow; there is no separate validator tool or CLI. - Confirm that required resource capacities can be supplied.
If the static check finds an issue, report:
✗ Workflow source is not ready to run
Reason: <first source-contract issue>
Otherwise:
✓ Workflow source is ready for run_flow
Capabilities
When the user asks what this skill can do ("你能帮我做什么 / 我能用这个干嘛"), lead with natural-language examples and mention saved-workflow reuse:
🐾 Workflow
用自然语言驱动多 Agent 工作流,也可以保存后按名称复用:
• "帮我写个工作流做 X / 帮我编排 ..."
*Truncated - read the full file at https://github.com/1DivSin/workflow/blob/60db31c55ea55e31d85b0cd61ab2c9b0df8c2880/src/SKI