Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
153 changes: 120 additions & 33 deletions openclaw.plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
"id": "clawflow",
"name": "ClawFlow",
"description": "The n8n for agents. Declarative, AI-native workflow engine — LLM-writable, Cloudflare-portable.",
"version": "1.3.0",
"skills": ["./skills/clawflow"],
"version": "1.3.1",
"skills": [
"./skills/clawflow"
],
"activation": {
"onStartup": true
},
Expand All @@ -26,59 +28,144 @@
"type": "object",
"additionalProperties": false,
"properties": {
"apiKey": { "type": "string" },
"defaultModel": { "type": "string" },
"baseUrl": { "type": "string" },
"defaultAgent": { "type": "string" },
"memoryDir": { "type": "string" },
"stateDir": { "type": "string" },
"maxNodeDurationMs": { "type": "number" },
"defaultProvider": { "type": "string" },
"apiKey": {
"type": "string"
},
"defaultModel": {
"type": "string"
},
"baseUrl": {
"type": "string"
},
"defaultAgent": {
"type": "string"
},
"memoryDir": {
"type": "string"
},
"stateDir": {
"type": "string"
},
"maxNodeDurationMs": {
"type": "number"
},
"defaultProvider": {
"type": "string"
},
"providers": {
"type": "object",
"additionalProperties": {
"type": "object",
"additionalProperties": false,
"properties": {
"baseUrl": { "type": "string" },
"api": { "type": "string", "enum": ["openai-completions", "anthropic-messages"] },
"apiKey": { "type": "string" },
"apiKeyEnv": { "type": "string" },
"models": { "type": "object", "additionalProperties": { "type": "string" } }
"baseUrl": {
"type": "string"
},
"api": {
"type": "string",
"enum": [
"openai-completions",
"anthropic-messages"
]
},
"apiKey": {
"type": "string"
},
"apiKeyEnv": {
"type": "string"
},
"models": {
"type": "object",
"additionalProperties": {
"type": "string"
}
}
},
"required": ["baseUrl"]
"required": [
"baseUrl"
]
}
},
"serve": {
"type": "object",
"properties": {
"port": { "type": "number" },
"path": { "type": "string" },
"flowsDir": { "type": "string" }
"port": {
"type": "number"
},
"path": {
"type": "string"
},
"flowsDir": {
"type": "string"
}
},
"required": ["port"]
"required": [
"port"
]
},
"approval": {
"type": "object",
"additionalProperties": false,
"properties": {
"enabled": { "type": "boolean" },
"skipSessionPatterns": { "type": "array", "items": { "type": "string" } },
"timeoutMs": { "type": "number" },
"timeoutBehavior": { "type": "string", "enum": ["allow", "deny"] }
"enabled": {
"type": "boolean"
},
"skipSessionPatterns": {
"type": "array",
"items": {
"type": "string"
}
},
"timeoutMs": {
"type": "number"
},
"timeoutBehavior": {
"type": "string",
"enum": [
"allow",
"deny"
]
}
}
}
}
},
"uiHints": {
"apiKey": { "label": "Anthropic API Key", "sensitive": true, "help": "Used when ANTHROPIC_API_KEY env var is not set" },
"defaultModel": { "label": "Default AI Model", "placeholder": "smart" },
"baseUrl": { "label": "Direct API Base URL", "placeholder": "https://api.anthropic.com" },
"defaultAgent": { "label": "Agent ID for do:agent nodes", "placeholder": "ops", "help": "OpenClaw agent ID to delegate agent tasks to. Uses --local (embedded) if unset." },
"memoryDir": { "label": "Memory Directory" },
"stateDir": { "label": "Flow State Directory" },
"maxNodeDurationMs": { "label": "Node Timeout (ms)", "placeholder": "30000" },
"serve": { "label": "Flow HTTP Server", "help": "Start an HTTP server that runs flows on POST. Requires at least port. Endpoint: POST /<basePath>/<flowName>/run with the JSON body as the flow's inputs." },
"approval": { "label": "Approval Gate", "help": "Prompt the user before flow_run executes. Set enabled=false to disable entirely. Add session-key substrings to skipSessionPatterns to bypass for unattended hooks (e.g. \"email\" for inbound-email automation)." }
"apiKey": {
"label": "Anthropic API Key",
"sensitive": true,
"help": "Used when ANTHROPIC_API_KEY env var is not set"
},
"defaultModel": {
"label": "Default AI Model",
"placeholder": "smart"
},
"baseUrl": {
"label": "Direct API Base URL",
"placeholder": "https://api.anthropic.com"
},
"defaultAgent": {
"label": "Agent ID for do:agent nodes",
"placeholder": "ops",
"help": "OpenClaw agent ID to delegate agent tasks to. Uses --local (embedded) if unset."
},
"memoryDir": {
"label": "Memory Directory"
},
"stateDir": {
"label": "Flow State Directory"
},
"maxNodeDurationMs": {
"label": "Node Timeout (ms)",
"placeholder": "30000"
},
"serve": {
"label": "Flow HTTP Server",
"help": "Start an HTTP server that runs flows on POST. Requires at least port. Endpoint: POST /<basePath>/<flowName>/run with the JSON body as the flow's inputs."
},
"approval": {
"label": "Approval Gate",
"help": "Prompt the user before flow_run executes. Set enabled=false to disable entirely. Add session-key substrings to skipSessionPatterns to bypass for unattended hooks (e.g. \"email\" for inbound-email automation)."
}
}
}
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@clawnify/clawflow",
"version": "1.3.0",
"version": "1.3.1",
"description": "The n8n for agents. A declarative, AI-native workflow format that agents can read, write, and run.",
"type": "module",
"main": "./dist/index.js",
Expand Down
18 changes: 11 additions & 7 deletions skills/clawflow/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ A flow is JSON with a `flow` name, an optional `env` block, and a `nodes` array.
| Node | Purpose | Key fields |
|------|---------|------------|
| `ai` | Single LLM call, structured or freeform | `prompt`, `schema`, `model`, `input`, `attachments` |
| `agent` | Delegate to a real OpenClaw agent (with tools, browser, etc.) | `task`, `agentId`, `session`, `tools` |
| `agent` | Delegate to a real OpenClaw agent (with tools, browser, etc.) | `task`, `agent`, `sessionKey`, `sessionId`, `channel`, `tools` |
| `exec` | Run a shell command deterministically (no AI) | `command`, `cwd` |
| `branch` | Multi-way routing with inline sub-flows per path | `on`, `paths`, `default` |
| `condition` | If/else with sub-node blocks that reconverge | `if`, `then`, `else` |
Expand All @@ -52,8 +52,12 @@ A flow is JSON with a `flow` name, an optional `env` block, and a `nodes` array.
- Use `do: exec` for deterministic operations (scripts, file processing, CLI tools) — never use `do: agent` for pure shell commands
- Use `do: agent` for tasks that need tools (browser, exec, memory, MCP, CLI) — delegates to a real OpenClaw agent
- Use `do: ai` for structured extraction and single-turn LLM calls
- Set `agentId: "clawflow"` on agent nodes to target a configured OpenClaw agent (a plain slug like `main`/`clawflow`, never a session key)
- Set `session: "agent:main:slack:channel:agent"` on agent nodes to run inside a specific existing session (e.g. a channel) — maps to `openclaw agent --session-key`. An `agent:`-prefixed key is self-scoping; a bare key (e.g. `incident-42`) is scoped by `agentId`. May be combined with `agentId`
- Agent-node selector fields mirror the `openclaw agent` CLI flags 1:1: `agent`→`--agent`, `sessionKey`→`--session-key`, `sessionId`→`--session-id`, `channel`→`--channel` (the old names `agentId`/`session` are deprecated aliases for `agent`/`sessionKey` and still work)
- Set `agent: "clawflow"` on agent nodes to target a configured OpenClaw agent (a plain slug like `main`/`clawflow`, never a session key)
- Set `sessionKey: "agent:main:slack:channel:agent"` on agent nodes to run inside a specific existing session (e.g. a channel) — maps to `--session-key`. An `agent:`-prefixed key is self-scoping; a bare key (e.g. `incident-42`) is scoped by `agent`. May be combined with `agent`
- Set `sessionId: "sess-9"` to target one explicit session by id (maps to `--session-id`) — the most specific selector, scoped by `agent`. Use `sessionKey` for channel/self-scoping keys, `sessionId` to resume a known id
- Set `channel: "slack"` to deliver the agent's reply on a specific channel (maps to `--channel`); omit to use the session's own channel
- `agent`, `sessionKey`, `sessionId`, and `channel` all support templates, so a prior node can compute the target (e.g. `agent: "{{ route.slug }}"`)
- Use `do: wait` with `for: approval` before any side effects that need human review — it pauses the flow, provides a token, and shows preview data to the approver
- Use `do: wait` with `for: event` to wait for external events (webhooks, signals)
- `do: condition` for boolean if/else, `do: branch` for multi-way value matching — both run inline sub-flows and reconverge
Expand Down Expand Up @@ -316,7 +320,7 @@ extract (agent) → parse (ai+schema) → loop:

### do: agent — exec approval setup

Agent nodes delegate to a real OpenClaw agent via `openclaw agent --agent <id> --message <task>` (or `--session-key <key>` when you set `session` instead of `agentId`). By default, the spawned agent uses the "main" profile, which may prompt for exec approval on every shell command — blocking unattended flows.
Agent nodes delegate to a real OpenClaw agent via `openclaw agent --agent <id> --message <task>` (or `--session-key <key>` when you set `sessionKey` instead of `agent`). By default, the spawned agent uses the "main" profile, which may prompt for exec approval on every shell command — blocking unattended flows.

To run agent nodes without interactive prompts, create a dedicated `clawflow` agent with full exec access:

Expand Down Expand Up @@ -364,20 +368,20 @@ openclaw approvals set --stdin <<'EOF'
EOF
```

**4. Set `agentId` on agent nodes:**
**4. Set `agent` on agent nodes:**

```json
{
"name": "research_topic",
"do": "agent",
"agentId": "clawflow",
"agent": "clawflow",
"task": "Research the latest trends in {{ inputs.topic }}",
"timeout": "240s",
"output": "research"
}
```

- `agentId` defaults to `"main"` if omitted (backward compatible)
- `agent` defaults to `"main"` if omitted (backward compatible)
- `security: "full"` + `ask: "off"` + `askFallback: "full"` = no prompts, all exec allowed
- The main interactive agent stays locked down with its own allowlist
- `exec-approvals.json` is per-agent — the `clawflow` entry only affects flow-spawned runs
Expand Down
Loading
Loading