首页openclaw插件 › ClawFlow — AI原生工作流引擎

代码插件 扫描中

ClawFlow — AI原生工作流引擎

v0.9.6

智能体的n8n,声明式、AI原生工作流格式,智能体可以读取、编写和运行。支持工作流编排、AI智能体集成和可视化工作流设计。

0· 6·0 当前
by @clawnify·MIT
下载插件包 项目主页
License
MIT
最后更新
2026/4/8
安全扫描
VirusTotal
Pending
查看报告
OpenClaw
扫描中
medium confidence
ClawFlow的代码和指令大部分与工作流/引擎插件匹配,但存在一些环境需求声明不匹配和SKILL.md中的提示注入信号,安装前应关注。
安全有层次,运行前请审查代码。

License

MIT

可自由使用、修改和再分发,需保留版权声明。

版本

latestv0.9.62026/3/26
● Pending

安装命令 点击复制

官方npx clawhub@latest install @clawnify/clawflow
镜像加速npx clawhub@latest install @clawnify/clawflow --registry https://cn.clawhub-mirror.com

插件文档

<p align="center" dir="auto"> <a target="_blank" rel="noopener noreferrer" href="https://www.clawnify.com"><img src="https://github.com/user-attachments/assets/ff7c98e6-ee70-4b4c-89ff-7c530369fdcb"; alt="ClawFlow" width="600" style="max-width: 100%;"></a> </p> <div class="markdown-heading" dir="auto"><h1 align="center" tabindex="-1" class="heading-element" dir="auto">ClawFlow</h1><a id="user-content-clawflow" class="anchor" aria-label="Permalink: ClawFlow" href="#clawflow"></a></div>

<p align="center"> <a href="https://www.npmjs.com/package/@clawnify/clawflow"><img src="https://img.shields.io/npm/v/@clawnify/clawflow?color=blue"; alt="npm"></a> <a href="https://github.com/clawnify/clawflow/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-MIT-green"; alt="License"></a> <a href="https://www.reddit.com/r/clawflow/"><img src="https://img.shields.io/badge/reddit-r%2Fclawflow-orange?logo=reddit&logoColor=white"; alt="Reddit"></a> <a href="https://www.clawnify.com"><img src="https://img.shields.io/badge/clawnify.com-website-blueviolet"; alt="Website"></a> </p>

The n8n for agents. A declarative, AI-native workflow format that agents can read, write, and run — without infrastructure.

Install

npm install @clawnify/clawflow

Or as an OpenClaw plugin:

openclaw plugins install @clawnify/clawflow

From source:

git clone https://github.com/clawnify/clawflow.git
cd clawflow && npm install && npm run build

Why ClawFlow

Workflows today are written for agents, not by them. Visual canvas tools require humans to click nodes. Code-first orchestration frameworks have too much surface area for LLMs to generate reliably.

ClawFlow is a workflow format designed from first principles for agents. Three rules drove every design decision:

  1. An LLM must be able to write a valid workflow in a single turn. If the format is too complex, agents hallucinate. If it's too simple, real workflows can't be expressed.
  1. The format is the asset, not the runtime. Write once, run as an OpenClaw plugin today, run in a standalone server tomorrow.
  1. AI nodes are first-class citizens. do: ai and do: agent are core primitives with structured output, model selection, and schema validation — not HTTP calls with extra steps.

Features

AI-Native

  • do: ai — structured LLM calls with schema validation and model selection (fast, smart, best)
  • do: agent — delegate to real agents with full tool access (browser, exec, memory, MCP, CLI)
  • Agent-writable — any LLM can generate a valid flow from a natural language description

Control Flow

  • do: branch — multi-way routing with inline sub-flows per path
  • do: condition — if/else with automatic reconvergence
  • do: loop — iterate over arrays
  • do: parallel — concurrent execution with all or race modes

Durability

  • Memoized state — completed nodes aren't re-run on resume
  • Approval gatesdo: wait pauses for human review, resumes with a token
  • External eventswaitForEvent blocks until an external system pushes data
  • Per-node retry — exponential, linear, or constant backoff on any node

Portability

  • OpenClaw plugin — run flows as agent tools today
  • Standalone runner — self-hosted Node.js server (coming soon)
  • Static validation — catch bad references and missing fields before execution
  • Draft/publish versioning — edit safely, publish when ready, run any version

Quick Example

A flow is JSON. No custom syntax, no new language — just structured data that any LLM can generate from a description.

{
  "flow": "support-triage",
  "description": "Classify a ticket, draft a reply, get approval, send it",
  "trigger": { "on": "webhook", "from": "helpdesk" },
  "nodes": [
    {
      "name": "classify",
      "do": "ai",
      "prompt": "Classify this ticket as billing, technical, or general",
      "input": "trigger.body",
      "schema": {
        "category": "billing | technical | general",
        "urgency": "low | medium | high",
        "summary": "string"
      },
      "model": "fast",
      "output": "classification"
    },
    {
      "name": "route",
      "do": "branch",
      "on": "classification.category",
      "paths": {
        "billing": [
          {
            "name": "handle-billing",
            "do": "agent",
            "task": "Draft a billing support reply for: {{ trigger.body }}",
            "output": "draft"
          }
        ],
        "technical": [
          {
            "name": "handle-technical",
            "do": "agent",
            "task": "Draft a technical support reply for: {{ trigger.body }}",
            "output": "draft"
          }
        ]
      },
      "default": [
        {
          "name": "handle-general",
          "do": "agent",
          "task": "Draft a general support reply for: {{ trigger.body }}",
          "output": "draft"
        }
      ]
    },
    {
      "name": "approve",
      "do": "wait",
      "for": "approval",
      "prompt": "Send this reply?\n\n{{ draft }}"
    },
    {
      "name": "send",
      "do": "http",
      "url": "https://helpdesk.example.com/api/reply",
      "method": "POST",
      "body": { "message": "{{ draft }}", "ticketId": "{{ trigger.id }}" },
      "retry": { "limit": 3, "delay": "2s", "backoff": "exponential" }
    }
  ]
}

Node Types

11 node types. This is intentional — the constraint is the feature. An LLM can reliably generate valid flows because there's nothing to hallucinate.

do: ai — LLM call

The most important node. A single LLM call that returns structured or freeform output.

{
  "name": "classify",
  "do": "ai",
  "prompt": "Classify this support ticket",
  "input": "trigger.body",
  "schema": {
    "category": "billing | technical | general",
    "confidence": "number",
    "summary": "string"
  },
  "model": "fast",
  "output": "classification"
}
FieldDescription
`prompt`The instruction to the model. Supports `{{ templates }}`.
`input`Dotted path to a value in flow state passed as context
`schema`Output shape. When set, enforces JSON mode. Keys are type hints.
`model``fast` (Gemini 3 Flash), `smart` (Claude Sonnet 4.6), `best` (Minimax M2.5), or any model string
`temperature`0–1, default 0 for deterministic workflow steps

Why schema matters: downstream nodes reference classification.category as a reliable string. Without schema, the output is freeform text and you're back to parsing.


do: agent — delegate to a real agent

Runs a task through a real OpenClaw agent with full tool access (browser, exec, memory, MCP, CLI). The agent decides its own path to a result.

{
  "name": "scrape",
  "do": "agent",
  "task": "Navigate to https://example.com and extract the pricing table as JSON",
  "agent": "main",
  "timeout": "120s",
  "output": "data"
}

On OpenClaw, this delegates to openclaw agent --agent <id> --message "...". The agent gets full tool access — browser, shell, file system, memory, MCP. Falls back to a single AI call if the CLI is unavailable (standalone mode).

FieldDescription
`task`The instruction to the agent. Supports `{{ templates }}`.
`agent`OpenClaw agent ID (e.g. `"main"`, `"ops"`). Uses config `defaultAgent` or `"main"` if omitted.
`input`Dotted path to context passed with the task
`tools`Hint for non-OpenClaw runtimes (OpenClaw agents have their own tool policy)

The distinction between ai and agent is intentional:

  • do: ai = deterministic, one-shot, structured output — use for classification, drafting, extraction
  • do: agent = open-ended, multi-step, uses tools — use for scraping, research, file operations

do: branch — multi-way routing

Routes the flow to a sub-flow based on a value in state. Each path is an array of nodes that executes as a self-contained block, then reconverges back into the main flow.

{
  "name": "route",
  "do": "branch",
  "on": "classification.category",
  "paths": {
    "billing": [
      { "name": "lookup-invoice", "do": "http", "url": "https://api.example.com/invoice/{{ trigger.id }}", "output": "invoice" },
      { "name": "draft-reply", "do": "ai", "prompt": "Draft billing reply for: {{ invoice }}", "output": "draft" }
    ],
    "technical": [
      { "name": "draft-reply", "do": "agent", "task": "Research and draft technical reply for: {{ trigger.body }}", "output": "draft" }
    ]
  },
  "default": [
    { "name": "draft-reply", "do": "ai", "prompt": "Draft a general reply for: {{ trigger.body }}", "output": "draft" }
  ]
}

Each path runs its full node sequence and merges state back. The default path handles any value not explicitly listed. No default + no matching path = runtime error (intentional — fail loudly).

Use branch for multi-way value matching, condition for boolean if/else logic. Both support full sub-flows and reconverge automatically.


do: condition — if/else with reconvergence

Runs inline sub-node blocks based on a boolean condition, then merges back into the main flow. Use condition for true/false logic, branch for multi-way value matching.

{
  "name": "check-transport",
  "do": "condition",
  "if": "extractOrder.transport_type == 'CLIENTE'",
  "then": [
    { "name": "pickup-note", "do": "code", "run": "'Client picks up'", "output": "note" }
  ],
  "else": [
    { "name": "delivery-note", "do": "code", "run": "'We deliver'", "output": "note" }
  ]
}
FieldDescription
`if`JS expression evaluated against flow state. Dotted paths are resolved.
`then`Nodes to run when condition is true
`else`Nodes to run when condition is false (optional — skipped if absent)

Supports comparison and logical operators:

"classification.priority == 'urgent'"
"validation.valid && items.length > 0"
"trigger.amount > 1000 || trigger.vip == true"

do: loop — iterate over a list

Runs a set of sub-nodes for each item in an array.

{
  "name": "process-tickets",
  "do": "loop",
  "over": "inbox.tickets",
  "as": "ticket",
  "nodes": [
    {
      "name": "summarize",
      "do": "ai",
      "prompt": "Summarize this ticket: {{ ticket }}",
      "output": "summary"
    }
  ],
  "output": "processed"
}

Iterations run sequentially. For concurrent execution, use do: parallel.


do: parallel — concurrent execution

Runs multiple nodes at the same time. Waits for all to complete (mode: "all") or the first to finish (mode: "race").

{
  "name": "research",
  "do": "parallel",
  "mode": "all",
  "nodes": [
    {
      "name": "web-search",
      "do": "agent",
      "task": "Search the web for recent cases of {{ topic }}",
      "output": "web_results"
    },
    {
      "name": "memory-lookup",
      "do": "memory",
      "action": "read",
      "key": "knowledge-{{ topic }}",
      "output": "memory_results"
    }
  ],
  "output": "research"
}

mode: "race" mirrors Cloudflare's Promise.race() pattern — the first branch to complete wins and the others are discarded. Useful for: try-cache-before-fetch, multi-model racing, fallback strategies.


do: http — external API call

{
  "name": "notify-slack",
  "do": "http",
  "url": "https://hooks.slack.com/services/{{ trigger.slackWebhook }}",
  "method": "POST",
  "body": { "text": "Ticket resolved: {{ classification.summary }}" },
  "retry": { "limit": 3, "delay": "1s", "backoff": "exponential" },
  "output": "slack_response"
}

All fields support {{ templates }}. Retry is strongly recommended for any outbound call.


do: memory — persistent key/value store

Read, write, or delete values that persist across flow runs.

{ "name": "save-result",  "do": "memory", "action": "write",  "key": "ticket-{{ trigger.id }}", "value": "{{ classification.category }}" }
{ "name": "load-history", "do": "memory", "action": "read",   "key": "ticket-{{ trigger.id }}", "output": "previous_category" }
{ "name": "cleanup",      "do": "memory", "action": "delete", "key": "ticket-{{ trigger.id }}" }

In the OpenClaw plugin, memory persists to ~/.openclaw/flow-memory/. In Cloudflare, it maps to KV or D1. Keys support templates.


do: wait — pause for human or external event

Two modes:

Approval gate — pauses the flow and returns a resumeToken. A human reviews and approves or denies via flow_resume.

{
  "name": "approve-send",
  "do": "wait",
  "for": "approval",
  "prompt": "Send this reply to the customer?\n\n{{ draft }}"
}

External event — blocks until an external system pushes the matching event via flow_send_event. Learned from Cloudflare's step.waitForEvent().

{
  "name": "await-payment",
  "do": "wait",
  "for": "event",
  "event": "stripe-payment-confirmed",
  "timeout": "24h",
  "output": "payment"
}

When a Stripe webhook arrives, the calling code does:

{ "tool": "flow_send_event", "instanceId": "...", "eventType": "stripe-payment-confirmed", "payload": { "amount": 4900 } }

The flow resumes with payment.amount = 4900 in state.


do: sleep — time-based pause

{ "name": "cool-down", "do": "sleep", "duration": "5m" }

Duration syntax: 30s, 5m, 2h, 1d. Maps directly to Cloudflare's step.sleep(). Does not count towards step limits.


do: code — inline JavaScript

{
  "name": "format-date",
  "do": "code",
  "input": "trigger.timestamp",
  "run": "new Date(input).toLocaleDateString('en-GB')",
  "output": "formatted_date"
}

Single expressions are returned automatically. Multi-statement bodies (containing ; or newlines) require an explicit return:

{
  "name": "calc",
  "do": "code",
  "input": "trigger",
  "run": "const total = input.price * input.qty;\nconst tax = total * 0.22;\nreturn { total, tax, grand: total + tax };",
  "output": "invoice"
}

No imports, no async, no filesystem access. state and input are frozen — return new values instead of mutating. For scripts or complex logic, use do: exec to run shell commands. For external APIs, use do: http.


Templates

Any string field supports {{ path.to.value }} interpolation resolved against flow state:

{{ trigger.body }}              # initial input
{{ classification.category }}   # node with output: "classification" → access .category
{{ trigger.user.email }}        # nested dotted path
{{ research.web_results }}      # array or object (serialized to JSON string)

Important: templates reference the output key, not the node name. If a node has "name": "get_data", "output": "api", reference it as {{ api }} — not {{ get_data }}.

Flow state starts as { trigger: <input> } and grows as nodes complete.


Retry Policy

Any node can define per-node retry behavior. Learned directly from Cloudflare's WorkflowStepConfig:

{
  "retry": {
    "limit": 3,
    "delay": "2s",
    "backoff": "exponential"
  }
}
FieldValuesDefault
`limit`integer1 (no retry)
`delay`duration string or ms`"0"`
`backoff``constant`, `linear`, `exponential``constant`

Strongly recommended on do: http and do: ai nodes. Do not use on do: wait — retrying approval gates makes no sense.


Flow State and Durability

Every flow run gets a unique instanceId. The runner persists state after every completed node to ~/.openclaw/flow-state/<instanceId>.json.

What this means in practice:

  • Gateway restarts mid-flow? Already-completed nodes are not re-run. The flow resumes from the last checkpoint.
  • A node that took 30 seconds to run won't run again on resume — its memoized output is loaded from disk.
  • An approval-gated flow can stay paused for days. The state survives indefinitely.

This is the lightweight equivalent of Cloudflare Durable Objects' memoization. Cloudflare does it at the infrastructure level with global durability. We do it at the file system level for local/self-hosted use.


Runtime Targets

The format is the spec. The runtime is swappable.

1. OpenClaw Plugin (current)

Eleven tools registered in OpenClaw:

ToolDoes
`flow_create`Create a new flow definition and save to file
`flow_delete`Soft-delete a flow (moves to `.clawflow/bin/`)
`flow_restore_from_bin`List bin contents or restore a deleted flow
`flow_run`Execute a flow (uses latest published version by default)
`flow_resume`Resume after an approval gate
`flow_send_event`Push an event into a waiting flow
`flow_status`Inspect any running or completed instance
`flow_list`List all flows with metadata, expected inputs, and version info
`flow_read`Read a flow definition (draft or specific version), inspect single nodes
`flow_publish`Publish current draft as a new numbered version
`flow_edit`Edit nodes in a flow definition (set, update, add, remove, move, wrap, revert, list)

Config:

数据来源:ClawHub ↗ · 中文优化:龙虾技能库
OpenClaw 技能定制 / 插件定制 / 私有工作流定制

免费技能或插件可能存在安全风险,如需更匹配、更安全的方案,建议联系付费定制

了解定制服务