feat(n8n-webhook): expand action bus starter workflow

This commit is contained in:
zap
2026-03-12 17:22:58 +00:00
parent 2757527957
commit 9dcc477a98
13 changed files with 386 additions and 97 deletions
@@ -10,10 +10,17 @@ It implements a real local OpenClaw → n8n router.
- accepts `POST /webhook/openclaw-action`
- normalizes incoming JSON into an action contract
- supports three live actions:
- supports these actions in the shipped asset:
- `append_log`
- `get_logs`
- `notify`
- `send_email_draft`
- `create_calendar_event`
- `approval_queue_add`
- `approval_queue_list`
- `approval_queue_resolve`
- `fetch_and_normalize_url`
- `inbound_event_filter`
- returns normalized JSON responses
- returns `400` for unknown actions
- returns `400` when required args are missing
@@ -33,13 +40,35 @@ Example stored record:
{"ts":"2026-03-12T07:00:00Z","source":"openclaw-action","request_id":"abc","text":"backup complete"}
```
### `get_logs`
### `send_email_draft` and `create_calendar_event`
- reads from workflow static data key:
- `actionLog`
- returns newest-first
- default `limit` is `20`
- clamps `limit` to `1..50`
- queue approval-gated proposals into workflow static data under key:
- `approvalQueue`
- keep the most recent `200` pending entries
- do **not** send email or create provider-side calendar events in the shipped starter workflow
- are designed to become safe provider-backed executors later once instance-local creds are bound in n8n
### `approval_queue_resolve`
- removes one item from `approvalQueue`
- appends the resolved entry into:
- `approvalHistory`
- supports optional notification on approval/rejection
### `fetch_and_normalize_url`
- fetches a remote `http` or `https` URL from inside n8n
- normalizes HTML/text/JSON into a single response shape
- returns title/excerpt/body text suitable for downstream summarization or logging
### `inbound_event_filter`
- classifies inbound events as `urgent`, `important`, `watch`, or `deduped`
- stores recent events in:
- `inboundEvents`
- stores recent dedupe keys in:
- `eventDedup`
- can fan out a notification for urgent/important non-duplicate events
### `notify`
@@ -49,18 +78,19 @@ Example stored record:
- `Discord Bot Auth`
- current targets mirror the already-working reminder workflow
## Why workflow static data for logs
## Why workflow static data first
Why this first:
- built-in, no extra credentials
- persists without guessing writable filesystem paths
- better fit than MinIO for small, recent operational breadcrumbs
- good fit for queues, recent breadcrumbs, and small operational state
- lets us implement safe approval-gated patterns immediately
When to use MinIO later:
- long retention
- rotated archives
- large/batched exports
- sharing logs outside n8n
When to add provider-backed steps later:
- email draft creation in Gmail/Outlook
- calendar writes in Google Calendar
- Airtable/Sheets append pipelines
- long-retention logs or external archival
## Intentional security choice
@@ -97,6 +127,11 @@ After import, set this manually in n8n:
- `assets/test-append-log.json`
- `assets/test-notify.json`
- `assets/test-send-email-draft.json`
- `assets/test-create-calendar-event.json`
- `assets/test-fetch-and-normalize-url.json`
- `assets/test-approval-queue-list.json`
- `assets/test-inbound-event-filter.json`
## Example tests
@@ -105,69 +140,73 @@ export N8N_WEBHOOK_SECRET='YOUR_SECRET_HERE'
scripts/call-action.sh append_log --args '{"text":"backup complete"}' --pretty
scripts/call-action.sh get_logs --args '{"limit":5}' --pretty
scripts/call-action.sh notify --args '{"title":"Workflow finished","message":"n8n router test"}' --pretty
scripts/call-action.sh send_email_draft --args-file assets/test-send-email-draft.json --pretty
scripts/call-action.sh create_calendar_event --args-file assets/test-create-calendar-event.json --pretty
scripts/call-action.sh fetch_and_normalize_url --args '{"url":"https://example.com"}' --pretty
scripts/call-action.sh approval_queue_list --args '{"limit":10,"include_history":true}' --pretty
scripts/call-action.sh inbound_event_filter --args-file assets/test-inbound-event-filter.json --pretty
```
## Expected success examples
### append_log
### send_email_draft
```json
{
"ok": true,
"request_id": "test-append-log-001",
"request_id": "test-email-draft-001",
"result": {
"action": "append_log",
"status": "logged",
"preview": {
"text": "backup complete"
},
"sink": {
"type": "workflow-static-data",
"key": "actionLog",
"retained_entries": 200
}
"action": "send_email_draft",
"status": "queued_for_approval",
"pending_id": "approval-abc123",
"approval_status": "pending"
}
}
```
### get_logs
### create_calendar_event
```json
{
"ok": true,
"request_id": "",
"request_id": "test-calendar-event-001",
"result": {
"action": "get_logs",
"action": "create_calendar_event",
"status": "queued_for_approval",
"pending_id": "approval-def456",
"approval_status": "pending"
}
}
```
### fetch_and_normalize_url
```json
{
"ok": true,
"request_id": "test-fetch-001",
"result": {
"action": "fetch_and_normalize_url",
"status": "ok",
"count": 1,
"total_retained": 1,
"retained_entries": 200,
"entries": [
{
"ts": "2026-03-12T08:42:37.615Z",
"source": "openclaw-action",
"request_id": "live-log-003",
"text": "n8n append_log static-data verification"
}
]
"url": "https://example.com/",
"title": "Example Domain",
"content_type": "text/html; charset=UTF-8"
}
}
```
### notify
### inbound_event_filter
```json
{
"ok": true,
"request_id": "test-notify-001",
"request_id": "test-inbound-001",
"result": {
"action": "notify",
"status": "sent",
"preview": {
"title": "Workflow finished",
"message": "n8n router test"
},
"targets": ["telegram", "discord"]
"action": "inbound_event_filter",
"status": "stored",
"classification": "urgent",
"duplicate": false,
"notified": true
}
}
```
+161 -28
View File
@@ -48,7 +48,7 @@ Recommended request shape:
}
```
## Live actions
## Live actions in the shipped workflow asset
### `append_log`
@@ -96,23 +96,6 @@ Behavior:
- max limit: `50`
- entries are returned newest-first
Success shape:
```json
{
"ok": true,
"request_id": "optional-uuid",
"result": {
"action": "get_logs",
"status": "ok",
"count": 2,
"total_retained": 7,
"retained_entries": 200,
"entries": []
}
}
```
### `notify`
Request:
@@ -130,21 +113,171 @@ Request:
Purpose:
- send the message through the currently configured Telegram + Discord notification targets
Success shape:
### `send_email_draft`
Request:
```json
{
"ok": true,
"request_id": "optional-uuid",
"result": {
"action": "notify",
"status": "sent",
"targets": ["telegram", "discord"]
"action": "send_email_draft",
"args": {
"to": ["will@example.com"],
"subject": "Draft daily brief",
"body_text": "Here is a draft daily brief for review."
}
}
```
## Failure shape
Purpose:
- queue an email draft proposal for approval
- does **not** send mail directly in the shipped starter workflow
Sink:
- type: `workflow-static-data`
- key: `approvalQueue`
- retained entries: `200`
### `create_calendar_event`
Request:
```json
{
"action": "create_calendar_event",
"args": {
"calendar": "primary",
"title": "Call with vendor",
"start": "2026-03-13T18:00:00Z",
"end": "2026-03-13T18:30:00Z",
"description": "Drafted from OpenClaw action bus."
}
}
```
Purpose:
- queue a calendar event proposal for approval
- does **not** write to a calendar provider directly in the shipped starter workflow
Sink:
- type: `workflow-static-data`
- key: `approvalQueue`
- retained entries: `200`
### `approval_queue_add`
Request:
```json
{
"action": "approval_queue_add",
"args": {
"kind": "manual",
"summary": "Review outbound customer reply",
"payload": {
"channel": "email"
},
"tags": ["approval", "customer"]
}
}
```
Purpose:
- add a generic pending approval item to the queue
### `approval_queue_list`
Request:
```json
{
"action": "approval_queue_list",
"args": {
"limit": 10,
"include_history": true
}
}
```
Purpose:
- inspect pending approval items
- optionally include recent resolved history
### `approval_queue_resolve`
Request:
```json
{
"action": "approval_queue_resolve",
"args": {
"id": "approval-abc123",
"decision": "approve",
"note": "Looks good",
"notify_on_resolve": true
}
}
```
Purpose:
- approve or reject a pending item
- moves resolved entries into `approvalHistory`
### `fetch_and_normalize_url`
Request:
```json
{
"action": "fetch_and_normalize_url",
"args": {
"url": "https://example.com/article",
"max_chars": 8000,
"timeout_ms": 10000
}
}
```
Purpose:
- fetch a URL inside n8n
- normalize content into a predictable summary-ready shape
Success shape includes:
- `url`
- `title`
- `content_type`
- `http_status`
- `excerpt`
- `body_text`
- `text_length`
- `truncated`
### `inbound_event_filter`
Request:
```json
{
"action": "inbound_event_filter",
"args": {
"source": "homelab",
"type": "alert",
"severity": "critical",
"summary": "Build failed on swarm cluster",
"notify": true
}
}
```
Purpose:
- dedupe and classify inbound events
- store recent events in workflow static data
- optionally notify on urgent/important events
Sinks:
- `inboundEvents`
- `eventDedup`
## Common failure shape
```json
{
@@ -160,6 +293,6 @@ Success shape:
## 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`, `get_logs`, `notify`.
- Use lowercase snake_case for JSON action names.
- Keep names explicit: `openclaw-ping`, `openclaw-action`, `append_log`, `approval_queue_resolve`.
- Avoid generic names like `run`, `task`, or `webhook1`.