Skip to content

Releases: clawnify/clawflow

v1.2.3

27 May 08:17
cd063a0

Choose a tag to compare

  • Send OpenRouter app attribution headers (HTTP-Referer: https://clawnify.com, X-OpenRouter-Title: Clawnify) on AI step inference calls so usage shows up on Clawnify's OpenRouter app page.

v1.2.2

20 May 08:34
423dc7d

Choose a tag to compare

Patch release.

Fixes

  • flow_run / flow_read / flow_publish failed with "require is not defined" whenever called with a file: argument. The plugin's resolveFlowFile / versionsDir / listVersions / readVersion helpers used inline require("path") / require("fs"), but the package ships as "type": "module" and tsc --module NodeNext emits those calls verbatim — so they blew up under the ESM plugin loader. Inline flows (no file:) sidestepped the broken path. Replaced with top-level node:fs / node:path imports.

v1.2.1 — README refresh

19 May 11:36
6dab623

Choose a tag to compare

Patch release: refreshed logo image in README. No source or behavior changes vs v1.2.0.

v1.2.0 — Plugin tool registration restored + configurable approvals

19 May 11:12
ab29f74

Choose a tag to compare

Restores flow_run / flow_create / etc. as native OpenClaw tools on hosts running ≥ 2026.4.26 and replaces the legacy boolean approval gate with a configurable one.

Fixes

  • Manifest now declares contracts.tools — OpenClaw 2026.5.2 enforces this as the manifest ownership contract for plugin tool registration. Without it, every registerTool() call was silently rejected and toolNames reported empty.
  • Plugin default exported from dist/index.js — the loader resolves through package.json.main. src/index.ts now re-exports the plugin default from ./plugin/index.js, so dist/index.js exposes both the OpenClaw entry and the public library symbols.
  • registerHook now passes a name — required by OpenClaw 2026.4.26. Missing-name failures previously killed the entire plugin load with Error: hook registration missing name.

New: configurable approval gate

Replaces the hardcoded requireApproval: true + plain prompt with a config-driven gate. Add to plugins.entries.clawflow.config:

{
  "approval": {
    "enabled": true,              // default true
    "skipSessionPatterns": [],    // substrings matched against ctx.sessionKey
    "timeoutMs": 300000,          // default 5 min
    "timeoutBehavior": "deny"     // default "deny"
  }
}

Returns the rich requireApproval: { title, description, severity, timeoutMs, timeoutBehavior } object the dashboard renders natively. Hosts that need unattended automation (e.g. inbound-webhook sessions) can list session-key substrings under skipSessionPatterns to bypass the gate.

Compatibility

  • compat.pluginApi / minGatewayVersion bumped to >=2026.5.2
  • build.openclawVersion bumped to 2026.5.12

Migration

If you were on @clawnify/clawflow@1.1.0:

  • No code changes required.
  • If you want to skip the approval prompt for specific session contexts, add approval.skipSessionPatterns to your plugins.entries.clawflow.config block in openclaw.json.

What's Changed

PR #35 (details) — four commits squashed.

v1.1.0 — custom step extension API

07 May 10:06
2ef2ea8

Choose a tag to compare

What's new

Public extension API for registering custom step types alongside built-ins (ai, code, http, …) — no fork required, no shoehorning logic into do: "code" blocks.

import { registerStepType } from "@clawnify/clawflow";

registerStepType({
  name: "clawnify_app",
  allowedKeys: ["app_id", "method", "path", "body"],
  validate: (input) => { /* return { ok, errors } */ },
  async run(input, ctx) {
    const res = await fetch(url, { signal: ctx.abortSignal });
    return { status: res.status, ok: res.ok, body: await res.json() };
  },
});

Flow JSON is unchanged — { "do": "clawnify_app", "name": "...", "app_id": "..." } resolves through the same dispatcher as built-ins.

API surface

  • registerStepType(def) — module-level registration on the default registry
  • StepRegistry class — register / get / has / names / clear
  • PluginConfig.customSteps — pass a private registry for test isolation or multi-runner scenarios
  • CustomStepContext handed to run():
    • state — frozen deep copy of flow state
    • env — resolved env (flow.env merged with process.env)
    • logger — node-prefixed debug / info / warn / error
    • abortSignal — per-flow AbortSignal (wired for future flow-level cancellation)
    • nodeName — the node's name field
    • resolveTemplate(str) — manually resolve {{ }} against live state

Behavior

  • Pre-resolves {{ template }} strings in input fields, mirroring do: http
  • Validator errors surface with the same { node, field, message } shape as native validation — indistinguishable from built-in errors
  • allowedKeys drives the existing unknown-field detection so typos in flow JSON still fail validation
  • Collisions with built-ins and duplicate registrations throw synchronously at register time
  • Unknown step at runtime fails fast with Unknown step type: "X". Registered custom steps: ...

Design notes

  • No new schema-library dependency. Validator is (input) => { ok, errors } — bring Zod / Ajv if you want.
  • No retry helper on ctx — node-level retry: already covers this.
  • AbortSignal is exposed now even though flow-cancel isn't wired yet, so the API doesn't break when it's added.

Compatibility

Purely additive — no breaking changes from 1.0.x. Existing flows and plugins continue to work unchanged.

v1.0.0 — trigger → inputs (breaking)

01 May 13:02
35fd5d3

Choose a tag to compare

Breaking changes

ClawFlow 1.0.0 removes the trigger concept from the flow format. Flows are now trigger-agnostic — the Clawnify platform resolves webhooks, cron, and manual triggers externally and passes a generic inputs payload.

What changed

  • FlowDefinition.trigger removed → replaced by optional inputs: Record<string, InputSpec> declaration block
  • {{ trigger.X }}{{ inputs.X }} in all templates
  • FlowState.triggerFlowState.inputs
  • HTTP server: startWebhookServer / WebhookServerOptsstartFlowServer / FlowServerOpts; endpoint /:flowName/webhook/:flowName/run
  • FlowTrigger type removedInputSpec type added
  • Plugin tool flow_create: trigger param → inputs param

Input validation

Declare inputs with required: true and they are validated at flow start (fail-fast before any node runs). Undeclared keys pass through silently. No declaration = anything-goes mode.

{
  "flow": "my-flow",
  "inputs": {
    "body": { "type": "string", "required": true },
    "id":   { "type": "string", "required": true }
  },
  "nodes": [...]
}

Migrating from 0.x

npx @clawnify/clawflow migrate <flows-dir> --dry   # preview
npx @clawnify/clawflow migrate <flows-dir>          # apply

The script rewrites flow files in-place: drops trigger: blocks, rewrites all {{ trigger.X }} templates, bare paths, and condition expressions.

v0.9.7

25 Apr 17:03
a2cc096

Choose a tag to compare

Skip webhook server on EADDRINUSE instead of crashing.

When clawflow's plugin register() is called in an environment where the gateway daemon already owns the webhook port (e.g. openclaw <anything> on a live VPS), the webhook listener now logs and returns instead of throwing. Avoids needing CLAWFLOW_NO_SERVE=1 for human CLI invocations.

PR #31

v0.9.6

13 Apr 07:31
0caf686

Choose a tag to compare

What's new

  • Compile-time key guards: NODE_KEYS is now derived from interfaces with CheckKeys<T, K> type guards. Adding a field to a node interface without updating the key tuple is a compile error — no more manual sync between types and validation.

v0.9.5

12 Apr 21:26
5546c09

Choose a tag to compare

What's new

  • Unknown field validation: Flow validation now rejects unrecognized keys on any node type, catching misplaced fields like branch paths placed as siblings of paths instead of inside it.

v0.9.2

05 Apr 21:45

Choose a tag to compare

Fix

  • Workspace fallback — defaults to $HOME/.openclaw/workspace when OPENCLAW_WORKSPACE env var and api.config.workspace are not set. Fixes EACCES errors on OpenClaw server where process.cwd() may not be writable.