feat(skill): add n8n action-bus helper

This commit is contained in:
zap
2026-03-12 06:51:15 +00:00
parent 7a44225481
commit 295809b161
4 changed files with 225 additions and 42 deletions

View File

@@ -9,4 +9,4 @@
- `openclaw-ping` webhook path tested end-to-end - `openclaw-ping` webhook path tested end-to-end
- Operating note: prefer narrow webhook-first integration rather than broad n8n admin/API access. - Operating note: prefer narrow webhook-first integration rather than broad n8n admin/API access.
- Will clarified the primary host LAN IP to use/document is `192.168.153.113`. - Will clarified the primary host LAN IP to use/document is `192.168.153.113`.
- Drafted local skill `skills/n8n-webhook` for authenticated webhook-first n8n integration, including `scripts/call-webhook.sh`, payload notes, and a successful package/validation run to `/tmp/n8n-skill-dist/n8n-webhook.skill`. - Drafted local skill `skills/n8n-webhook` for authenticated webhook-first n8n integration, including `scripts/call-webhook.sh`, `scripts/call-action.sh`, payload notes, and a successful package/validation run to `/tmp/n8n-skill-dist/n8n-webhook.skill`.

View File

@@ -1,6 +1,6 @@
--- ---
name: n8n-webhook name: n8n-webhook
description: Trigger authenticated local n8n webhooks on the LAN for OpenClaw-to-n8n integration. Use when calling safe, narrow workflows on the dedicated local n8n-agent instance, such as ping/test endpoints, action-bus style workflows, notifications, logging, or other preapproved webhook entrypoints. Do not use for broad n8n admin/API management, workflow mutation, credential management, or unrestricted orchestration. description: Trigger authenticated local n8n webhooks on the LAN for OpenClaw-to-n8n integration. Use when calling safe, narrow workflows on the dedicated local n8n-agent instance, such as ping/test endpoints, an action-bus style router workflow, notifications, logging, or other preapproved webhook entrypoints. Do not use for broad n8n admin/API management, workflow mutation, credential management, or unrestricted orchestration.
--- ---
# N8n Webhook # N8n Webhook
@@ -15,11 +15,12 @@ Keep the integration narrow: let OpenClaw decide what to do, and let n8n execute
## Policy ## Policy
1. Prefer named webhook entrypoints over generic admin APIs. 1. Prefer named webhook entrypoints over generic admin APIs.
2. Send JSON and expect JSON back. 2. Prefer one small router webhook (`openclaw-action`) when several agent-safe actions are needed.
3. Use header auth by default (`x-openclaw-secret`). 3. Send JSON and expect JSON back.
4. Use `/webhook-test/` only while building/editing a workflow. 4. Use header auth by default (`x-openclaw-secret`).
5. Surface non-2xx responses clearly instead of pretending success. 5. Use `/webhook-test/` only while building/editing a workflow.
6. If a new workflow is needed, define its request/response contract before wiring callers. 6. Surface non-2xx responses clearly instead of pretending success.
7. If a new workflow is needed, define its request/response contract before wiring callers.
## Quick usage ## Quick usage
@@ -29,40 +30,56 @@ Set the shared secret once for the shell session:
export N8N_WEBHOOK_SECRET='replace-me' export N8N_WEBHOOK_SECRET='replace-me'
``` ```
Call a production webhook: Call a production webhook directly:
```bash ```bash
scripts/call-webhook.sh openclaw-ping --data '{"message":"hello from OpenClaw"}' scripts/call-webhook.sh openclaw-ping --data '{"message":"hello from OpenClaw"}'
``` ```
Call the preferred action-bus route:
```bash
scripts/call-action.sh append_log --args '{"text":"backup complete"}'
```
Call a test webhook while editing a flow: Call a test webhook while editing a flow:
```bash ```bash
scripts/call-webhook.sh openclaw-ping --test --data '{"message":"hello from OpenClaw"}' scripts/call-action.sh notify --args '{"message":"hello from OpenClaw"}' --test --pretty
```
Pretty-print JSON response:
```bash
scripts/call-webhook.sh openclaw-ping --pretty --data '{"message":"hello"}'
``` ```
## Workflow ## Workflow
### Call an existing safe webhook ### Call an existing safe webhook directly
1. Confirm the target webhook path is already intended for agent use. Use `scripts/call-webhook.sh` when the path is already defined and there is no benefit to the action-bus wrapper.
2. Use `scripts/call-webhook.sh` with JSON input.
3. Treat any non-2xx response as a failure that needs investigation.
Current known endpoint: Current known direct endpoint:
- `openclaw-ping` — basic end-to-end connectivity check - `openclaw-ping` — basic end-to-end connectivity check
### Call the action bus
Use `scripts/call-action.sh` when the n8n side exposes a router webhook such as `openclaw-action`.
Payload shape:
```json
{
"action": "append_log",
"args": {
"text": "backup complete"
},
"request_id": "optional-uuid"
}
```
This keeps the external surface small while letting n8n route internally.
### Add a new webhook-backed capability ### Add a new webhook-backed capability
1. Write down the webhook path, required auth, request JSON, and response JSON. 1. Write down the webhook path, required auth, request JSON, and response JSON.
2. If the shape is more than trivial, read `references/payloads.md` first. 2. If the path should become part of the shared action bus, document the `action` name and `args` shape in `references/payloads.md`.
3. Keep the first version small and explicit. 3. Keep the first version small and explicit.
4. Only add the new endpoint to regular use after a successful `/webhook-test/` run. 4. Only add the new endpoint to regular use after a successful `/webhook-test/` run.
@@ -71,8 +88,10 @@ Current known endpoint:
- `N8N_BASE_URL` — override base URL (default `http://192.168.153.113:18808`) - `N8N_BASE_URL` — override base URL (default `http://192.168.153.113:18808`)
- `N8N_WEBHOOK_SECRET` — required shared secret for authenticated calls - `N8N_WEBHOOK_SECRET` — required shared secret for authenticated calls
- `N8N_SECRET_HEADER` — header name (default `x-openclaw-secret`) - `N8N_SECRET_HEADER` — header name (default `x-openclaw-secret`)
- `N8N_ACTION_PATH` — router path for `call-action.sh` (default `openclaw-action`)
## Resources ## Resources
- `scripts/call-webhook.sh` — authenticated POST helper for local n8n webhooks - `scripts/call-webhook.sh` — authenticated POST helper for direct local n8n webhooks
- `references/payloads.md` — suggested request/response contracts and naming conventions - `scripts/call-action.sh` — wrapper for action-bus style calls against `openclaw-action`
- `references/payloads.md` — request/response contracts and naming conventions

View File

@@ -25,52 +25,88 @@ Recommended success response:
} }
``` ```
## Recommended contract for new endpoints ## Preferred router endpoint
Prefer a stable JSON shape like: ### `openclaw-action`
Purpose:
- keep the external n8n surface small
- route several agent-safe operations behind one authenticated webhook
Recommended request shape:
```json
{
"action": "append_log",
"args": {
"text": "backup complete"
},
"request_id": "optional-uuid"
}
```
Recommended success response:
```json ```json
{ {
"ok": true, "ok": true,
"request_id": "optional-uuid", "request_id": "optional-uuid",
"result": { "result": {
"...": "workflow-specific payload" "status": "accepted"
} }
} }
``` ```
On failure, return a non-2xx status plus: Recommended failure response:
```json ```json
{ {
"ok": false, "ok": false,
"error": { "error": {
"code": "short-machine-code", "code": "unknown_action",
"message": "human-readable summary" "message": "action is not supported"
} }
} }
``` ```
## Naming guidance ## Suggested initial actions
- Use lowercase kebab-case webhook paths. ### `append_log`
- Keep names explicit: `openclaw-ping`, `openclaw-action`, `append-log`, `send-notify`.
- Avoid generic names like `run`, `task`, or `webhook1`.
## Suggested action-bus pattern Request:
If multiple agent-safe actions are needed, prefer one router webhook such as `openclaw-action`.
Request shape:
```json ```json
{ {
"action": "append_log", "action": "append_log",
"args": { "args": {
"text": "backup finished" "text": "backup complete"
}, }
"request_id": "optional-uuid"
} }
``` ```
That keeps the external surface small while letting n8n route internally. Purpose:
- append a short line to a known log or tracking sink
### `notify`
Request:
```json
{
"action": "notify",
"args": {
"message": "workflow finished",
"title": "optional title"
}
}
```
Purpose:
- send a small notification through a known downstream channel
## Naming guidance
- Use lowercase kebab-case for webhook paths.
- Use lowercase snake_case or kebab-case consistently for action names; prefer snake_case for JSON actions if using switch/router logic.
- Keep names explicit: `openclaw-ping`, `openclaw-action`, `append_log`, `notify`.
- Avoid generic names like `run`, `task`, or `webhook1`.

View File

@@ -0,0 +1,128 @@
#!/usr/bin/env bash
set -euo pipefail
usage() {
cat <<'EOF'
Usage:
scripts/call-action.sh <action> [--args '{"k":"v"}'] [--args-file args.json] [--request-id <id>] [--path openclaw-action] [--test] [--pretty] [--dry-run]
Environment:
N8N_ACTION_PATH Default router webhook path (default: openclaw-action)
N8N_WEBHOOK_SECRET Shared secret for header auth
N8N_BASE_URL Base n8n URL (default: http://192.168.153.113:18808)
N8N_SECRET_HEADER Header name (default: x-openclaw-secret)
Examples:
scripts/call-action.sh append_log --args '{"text":"backup complete"}'
scripts/call-action.sh notify --args-file notify.json --test --pretty
EOF
}
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
CALL_WEBHOOK="$SCRIPT_DIR/call-webhook.sh"
ACTION_PATH="${N8N_ACTION_PATH:-openclaw-action}"
ACTION=""
ARGS='{}'
ARGS_FILE=""
REQUEST_ID=""
MODE_FLAG=""
PRETTY=0
DRY_RUN=0
EXTRA_ARGS=()
while [[ $# -gt 0 ]]; do
case "$1" in
--help|-h)
usage
exit 0
;;
--args)
ARGS="${2:?missing value for --args}"
shift 2
;;
--args-file)
ARGS_FILE="${2:?missing value for --args-file}"
shift 2
;;
--request-id)
REQUEST_ID="${2:?missing value for --request-id}"
shift 2
;;
--path)
ACTION_PATH="${2:?missing value for --path}"
shift 2
;;
--test)
MODE_FLAG="--test"
shift
;;
--prod)
MODE_FLAG="--prod"
shift
;;
--pretty)
PRETTY=1
shift
;;
--dry-run)
DRY_RUN=1
shift
;;
--*)
echo "Unknown option: $1" >&2
usage >&2
exit 2
;;
*)
if [[ -z "$ACTION" ]]; then
ACTION="$1"
else
EXTRA_ARGS+=("$1")
fi
shift
;;
esac
done
if [[ -z "$ACTION" ]]; then
usage >&2
exit 2
fi
if [[ ${#EXTRA_ARGS[@]} -gt 0 ]]; then
echo "Unexpected extra arguments: ${EXTRA_ARGS[*]}" >&2
exit 2
fi
if [[ -n "$ARGS_FILE" ]]; then
ARGS="$(cat "$ARGS_FILE")"
fi
PAYLOAD="$({
python3 - <<'PY' "$ACTION" "$ARGS" "$REQUEST_ID"
import json, sys
action = sys.argv[1]
args = json.loads(sys.argv[2])
request_id = sys.argv[3]
if not isinstance(args, dict):
raise SystemExit('Action args must decode to a JSON object.')
payload = {
'action': action,
'args': args,
}
if request_id:
payload['request_id'] = request_id
print(json.dumps(payload, separators=(',', ':')))
PY
} )"
CMD=("$CALL_WEBHOOK" "$ACTION_PATH" --data "$PAYLOAD")
[[ -n "$MODE_FLAG" ]] && CMD+=("$MODE_FLAG")
[[ "$PRETTY" -eq 1 ]] && CMD+=(--pretty)
[[ "$DRY_RUN" -eq 1 ]] && CMD+=(--dry-run)
exec "${CMD[@]}"