From ffe7a6bad6d18231f71af2d66851425ba059e178 Mon Sep 17 00:00:00 2001 From: zap Date: Thu, 12 Mar 2026 21:24:41 +0000 Subject: [PATCH] docs(n8n-webhook): add operator approval runbook --- HANDOFF.md | 13 +- WIP.md | 75 ++++++++--- memory/2026-03-12.md | 25 ++++ skills/n8n-webhook/SKILL.md | 4 + .../n8n-webhook/references/openclaw-action.md | 120 +++++++++++++++++- skills/n8n-webhook/references/payloads.md | 24 ++++ 6 files changed, 234 insertions(+), 27 deletions(-) diff --git a/HANDOFF.md b/HANDOFF.md index 6453da6..408e02f 100644 --- a/HANDOFF.md +++ b/HANDOFF.md @@ -4,7 +4,7 @@ Immediate baton-pass for the next fresh implementation session. ## Current objective -Run operator/polish pass (3/3): tighten operator docs, approval policy clarity, recurring verification flow, and low-noise execution reporting now that Gmail + Calendar passes are complete. +Operator/polish pass is complete. Next fresh session should decide whether Drive / Docs / Sheets need action-bus verbs at all, while preserving the approval/history contract that now exists for Gmail + Calendar. ## Use these state files first 1. `WIP.md` — full standing plan and checkpoints @@ -59,14 +59,13 @@ Run operator/polish pass (3/3): tighten operator docs, approval policy clarity, - Added docs/test payloads/validator coverage for the expanded calendar contract. ## Highest-priority next actions -1. Add a compact operator command/reference section for common approval flows. -2. Add one or two canned recurring verification flows (queue → approve → verify → cleanup). -3. Decide/document approval defaults clearly per action family. -4. Improve low-noise execution/result reporting in approval history. +1. Decide whether Drive / Docs / Sheets need action-bus verbs or should stay direct-tool only. +2. If new Google actions are added, keep approval defaults explicit by family (`notification`, `gmail`, `calendar`, `manual`). +3. Preserve compact operator reporting (`pending_compact`, `history_compact`, `summary_line`, `result_refs`) for any new approval-backed actions. ## Success criteria for the next session -- Operator/polish pass completed with docs/playbook/history-reporting improvements. -- Approval defaults are explicit and easy to skim. +- Clear go/no-go decision on expanding beyond Gmail + Calendar. +- Any new verbs inherit the same safe approval defaults and low-noise history contract. - `WIP.md` and memory updated with concrete evidence. - Meaningful commit(s) captured. diff --git a/WIP.md b/WIP.md index f4bde81..23c496c 100644 --- a/WIP.md +++ b/WIP.md @@ -105,10 +105,10 @@ Started: `2026-03-12` - [ ] Decide whether Drive/Docs/Sheets need action-bus verbs next or can stay direct-tool only for now ### Then polish the operator experience -- [ ] Add a compact operator command/reference section for common approval flows -- [ ] Add one or two canned test payloads for real bridge verification flows -- [ ] Decide whether some Google actions should stay approval-gated by default -- [ ] Add low-noise reporting so history clearly shows: +- [x] Add a compact operator command/reference section for common approval flows +- [x] Add one or two canned test payloads for real bridge verification flows +- [x] Decide/document approval defaults clearly per action family +- [x] Add low-noise reporting so history clearly shows: - queued - approved/rejected - executed @@ -139,12 +139,12 @@ Planned passes: - added `delete_calendar_event` - added `list_upcoming_events` - updated workflow contract/docs/test payloads/bridge + WIP evidence -3. Operator/polish pass: - - decide approval defaults for each action - - add low-noise execution/result reporting - - add compact operator command/reference docs - - add one or two canned recurring test payloads - - update `WIP.md` with evidence before ending the pass +3. Operator/polish pass: ✅ complete + - documented approval defaults by action family (`notification`, `gmail`, `calendar`, `manual`) + - added low-noise queue/history reporting (`pending_compact`, `history_compact`, `summary_line`, `result_refs`) + - added compact operator command/reference docs + - added two canned recurring verification payloads + - refreshed `WIP.md` with evidence before ending the pass ## Fresh-session proof refresh (2026-03-12 19:44Z) - Re-ran both target proofs through the real approval-routed path in a clean implementation session. @@ -220,15 +220,60 @@ Targeted verification evidence: - `calendar_event_delete` → `gog calendar delete primary example-calendar-event-id --account will@example.com --json --no-input --force --send-updates none --dry-run` - `python3 -m py_compile skills/n8n-webhook/scripts/resolve-approval-with-gog.py` passed. +## Operator/polish pass 3 completion (2026-03-12) +Implemented in this pass: +- added explicit approval-family defaults in the shipped workflow + docs: + - `notification` → required `high` + - `gmail` read-only (`list_email_drafts`) → required `low` + - `gmail` mutating (`send_email_draft`, `delete_email_draft`, `send_gmail_draft`) → required `high` + - `calendar` read-only (`list_upcoming_events`) → required `low` + - `calendar` mutating (`create_calendar_event`, `update_calendar_event`, `delete_calendar_event`) → required `high` +- added compact operator-facing queue/history fields in the workflow: + - `payload_preview` + - `operator.summary_line` + - `operator.execution_state` + - `operator.result_refs` + - `approval_queue_list.result.pending_compact` + - `approval_queue_list.result.history_compact` + - `approval_queue_resolve.result.item_compact` + - `approval_history_attach_execution.result.item_compact` +- taught the host bridge to attach `execution.summary` + `execution.result_refs` +- added recurring verification payloads: + - `skills/n8n-webhook/assets/test-verify-email-draft-cycle.json` + - `skills/n8n-webhook/assets/test-verify-calendar-event-cycle.json` +- added operator runbook / recurring verification docs in: + - `skills/n8n-webhook/references/openclaw-action.md` + - `skills/n8n-webhook/references/payloads.md` + - `skills/n8n-webhook/SKILL.md` + +Targeted verification evidence: +- `python3 skills/n8n-webhook/scripts/validate-workflow.py skills/n8n-webhook/assets/openclaw-action.workflow.json` + - result: `OK: workflow asset structure looks consistent` + - validator now also checks the two new recurring verification payload files +- `python3 -m py_compile skills/n8n-webhook/scripts/resolve-approval-with-gog.py` + - result: passed +- bridge helper proof via direct import/execution: + - `execution_result_refs('gmail.drafts.create', {'draft': {'id': 'r-proof-draft-123'}})` → `{'draft_id': 'r-proof-draft-123'}` + - `execution_summary(...)` → `gmail.drafts.create draft created (draft_id=r-proof-draft-123)` + - `execution_result_refs('calendar.create', {'event': {'id': 'evt-proof-456'}, 'calendar': 'primary'})` → `{'event_id': 'evt-proof-456', 'calendar': 'primary'}` + - `execution_summary(...)` → `calendar.create event created (event_id=evt-proof-456, calendar=primary)` +- workflow asset inspection confirmed low-noise operator fields are present: + - `pending_compact` + - `history_compact` + - `summary_line` + - `result_refs` + - `default_mode` + - `approval.family` +- recurring verification payload identity proofs: + - `test-verify-email-draft-cycle.json` → request id `verify-email-draft-cycle-001` + - `test-verify-calendar-event-cycle.json` → request id `verify-calendar-event-cycle-001` + ## Next-session handoff For the next fresh implementation session, start from `HANDOFF.md` + `WIP.md` rather than from old chat context. Immediate target: -- operator/polish pass only: - - add a compact operator command/reference section for common approval flows - - add one or two canned recurring verification flows - - decide/document approval defaults clearly per action family - - improve low-noise execution/result reporting in history +- decide whether Drive / Docs / Sheets actually need action-bus verbs or can remain direct-tool workflows for now +- if Google action coverage expands again, preserve the same approval-family defaults and compact history contract - refresh WIP/memory/tasks before ending ## Relevant files diff --git a/memory/2026-03-12.md b/memory/2026-03-12.md index a735109..ae9a20b 100644 --- a/memory/2026-03-12.md +++ b/memory/2026-03-12.md @@ -198,3 +198,28 @@ - `gog calendar update primary example-calendar-event-id --account will@example.com --json --no-input --send-updates none --summary Updated call with vendor --from 2026-03-13T18:15:00Z --to 2026-03-13T18:45:00Z --description Updated by OpenClaw action bus. --location Updated room --dry-run` - `gog calendar delete primary example-calendar-event-id --account will@example.com --json --no-input --force --send-updates none --dry-run` - `python3 -m py_compile skills/n8n-webhook/scripts/resolve-approval-with-gog.py` passed. + +## Operator/polish pass 3 (fresh subagent implementation, locally verified) +- Added explicit approval families + defaults across the n8n action bus: + - notification → required/high + - gmail read-only → required/low + - gmail mutating → required/high + - calendar read-only → required/low + - calendar mutating → required/high +- Added low-noise operator/history reporting in the workflow: + - `payload_preview` + - `operator.summary_line` + - `operator.execution_state` + - `operator.result_refs` + - compact list surfaces: `pending_compact`, `history_compact`, `item_compact` +- Extended the host bridge so attached execution metadata now includes: + - `execution.summary` + - `execution.result_refs` +- Added recurring verification payloads with stable proof IDs: + - `skills/n8n-webhook/assets/test-verify-email-draft-cycle.json` → `verify-email-draft-cycle-001` + - `skills/n8n-webhook/assets/test-verify-calendar-event-cycle.json` → `verify-calendar-event-cycle-001` +- Local verification proofs: + - workflow validator passed after the operator/history changes + - bridge helper proof: `gmail.drafts.create` sample result produced `draft_id = r-proof-draft-123` + - bridge helper proof: `calendar.create` sample result produced `event_id = evt-proof-456`, `calendar = primary` + - workflow asset string checks confirmed presence of `pending_compact`, `history_compact`, `summary_line`, `result_refs`, `default_mode`, and `approval.family` diff --git a/skills/n8n-webhook/SKILL.md b/skills/n8n-webhook/SKILL.md index 2c6bde2..51b6b75 100644 --- a/skills/n8n-webhook/SKILL.md +++ b/skills/n8n-webhook/SKILL.md @@ -43,6 +43,8 @@ Keep the integration narrow: let OpenClaw decide what to do, and let n8n execute - `assets/test-list-upcoming-events.json` - `assets/test-update-calendar-event.json` - `assets/test-delete-calendar-event.json` + - `assets/test-verify-email-draft-cycle.json` + - `assets/test-verify-calendar-event-cycle.json` ## Quick usage @@ -65,6 +67,7 @@ scripts/call-action.sh append_log --args '{"text":"backup complete"}' --request- scripts/call-action.sh get_logs --args '{"limit":5}' --pretty scripts/call-action.sh list_email_drafts --args '{"max":10}' --pretty scripts/call-action.sh list_upcoming_events --args '{"days":7,"max":10}' --pretty +scripts/call-action.sh approval_queue_list --args '{"limit":5,"include_history":true}' --pretty ``` Call a test webhook while editing a flow: @@ -159,6 +162,7 @@ Practical note: - unattended execution needs `GOG_KEYRING_PASSWORD` available to the executor because `gog`'s file keyring cannot prompt in non-TTY automation - the included bridge auto-loads `/home/openclaw/.openclaw/credentials/gog.env` when present, so you can keep `GOG_ACCOUNT` and `GOG_KEYRING_PASSWORD` there with mode `600` - for safe plumbing tests without touching Google state, add `--dry-run` +- approval queue/history reads now expose compact `pending_compact` / `history_compact` entries plus `summary_line` + `result_refs` for low-noise operator review ### Add a new webhook-backed capability diff --git a/skills/n8n-webhook/references/openclaw-action.md b/skills/n8n-webhook/references/openclaw-action.md index 3582f31..fdb567e 100644 --- a/skills/n8n-webhook/references/openclaw-action.md +++ b/skills/n8n-webhook/references/openclaw-action.md @@ -75,13 +75,41 @@ Behavior: - do **not** execute Gmail/Calendar side effects directly in the shipped starter workflow - are intended for host-side execution via the included `gog` bridge after explicit approval resolution -Approval policy defaults: -- `send_email_draft`, `delete_email_draft`, `send_gmail_draft` / `send_approved_email`, `create_calendar_event`, `update_calendar_event`, `delete_calendar_event` +Approval policy defaults by action family: +- notification family + - `send_notification_draft` + - `approval.family = "notification"` - `approval.required = true` - `approval.mutation_level = "high"` -- `list_email_drafts`, `list_upcoming_events` - - `approval.required = true` - - `approval.mutation_level = "low"` (read-only action, still routed through approval queue for explicit operator acknowledgement + audit trail) + - approved items execute inline in n8n via the existing `notify` path +- Gmail family + - read-only: `list_email_drafts` + - `approval.family = "gmail"` + - `approval.required = true` + - `approval.mutation_level = "low"` + - still queued so operators must explicitly acknowledge host-side Gmail reads + - mutating: `send_email_draft`, `delete_email_draft`, `send_gmail_draft` / `send_approved_email` + - `approval.family = "gmail"` + - `approval.required = true` + - `approval.mutation_level = "high"` +- Calendar family + - read-only: `list_upcoming_events` + - `approval.family = "calendar"` + - `approval.required = true` + - `approval.mutation_level = "low"` + - mutating: `create_calendar_event`, `update_calendar_event`, `delete_calendar_event` + - `approval.family = "calendar"` + - `approval.required = true` + - `approval.mutation_level = "high"` +- manual/generic approvals + - `approval_queue_add` + - no automatic side effect is implied; the operator decides what the queued item means + +Queue/history entries now also carry compact operator-facing fields for low-noise review: +- `approvalQueue[].payload_preview` +- `approvalQueue[].operator.summary_line` +- `approvalHistory[].operator.execution_state` +- `approvalHistory[].operator.result_refs` ### `approval_queue_resolve` @@ -90,12 +118,20 @@ Approval policy defaults: - `approvalHistory` - supports optional notification on approval/rejection - executes notification drafts inline when the approved item kind is `notification` +- returns both the full resolved item and a compact operator view at: + - `result.item_compact` ### `approval_history_attach_execution` - patches an existing resolved history item in `approvalHistory` - designed for host-side executors that run outside n8n itself - used by the included `scripts/resolve-approval-with-gog.py` bridge to attach Gmail/Calendar execution results +- the updated history entry now includes low-noise operator metadata such as: + - `operator.summary_line` + - `operator.execution_state` + - `operator.result_refs` + - `execution.summary` +- returns both the full item and `result.item_compact` ### `fetch_and_normalize_url` @@ -181,6 +217,8 @@ After import, set this manually in n8n: - `assets/test-list-upcoming-events.json` - `assets/test-update-calendar-event.json` - `assets/test-delete-calendar-event.json` +- `assets/test-verify-email-draft-cycle.json` +- `assets/test-verify-calendar-event-cycle.json` - `assets/test-fetch-and-normalize-url.json` - `assets/test-approval-queue-list.json` - `assets/test-inbound-event-filter.json` @@ -202,6 +240,8 @@ scripts/call-action.sh create_calendar_event --args-file assets/test-create-cale scripts/call-action.sh list_upcoming_events --args-file assets/test-list-upcoming-events.json --pretty scripts/call-action.sh update_calendar_event --args-file assets/test-update-calendar-event.json --pretty scripts/call-action.sh delete_calendar_event --args-file assets/test-delete-calendar-event.json --pretty +scripts/call-action.sh --args-file assets/test-verify-email-draft-cycle.json --pretty +scripts/call-action.sh --args-file assets/test-verify-calendar-event-cycle.json --pretty scripts/call-action.sh fetch_and_normalize_url --args '{"url":"http://192.168.153.113:18808/healthz"}' --pretty scripts/call-action.sh fetch_and_normalize_url --args '{"url":"https://example.com","skip_ssl_certificate_validation":true}' --pretty scripts/call-action.sh approval_queue_list --args '{"limit":10,"include_history":true}' --pretty @@ -209,6 +249,76 @@ scripts/call-action.sh inbound_event_filter --args-file assets/test-inbound-even python3 scripts/resolve-approval-with-gog.py --id --decision approve --dry-run ``` +## Operator command reference + +Common approval flows: + +```bash +# 1) inspect the queue with both full and compact views +scripts/call-action.sh approval_queue_list --args '{"limit":10,"include_history":true}' --pretty + +# 2) reject an item without host-side execution +scripts/call-action.sh approval_queue_resolve \ + --args '{"id":"approval-abc123","decision":"reject","note":"not safe to run"}' \ + --pretty + +# 3) approve through the host bridge, but keep it side-effect free +python3 scripts/resolve-approval-with-gog.py --id approval-abc123 --decision approve --dry-run + +# 4) approve for real through the host bridge +python3 scripts/resolve-approval-with-gog.py --id approval-abc123 --decision approve + +# 5) re-check recent history in compact form +scripts/call-action.sh approval_queue_list --args '{"limit":5,"include_history":true}' --pretty +``` + +What to look for in low-noise history output: +- `result.pending_compact[]` and `result.history_compact[]` +- `summary_line` for a one-line operator digest +- `execution_state` for `pending`, `awaiting_host_execution`, `dry_run`, `executed`, or `failed` +- `result_refs` for durable IDs such as `draft_id`, `message_id`, or `event_id` + +## Canned recurring verification flows + +### Gmail draft queue → approve → verify → cleanup + +1. Queue the canned payload: + +```bash +scripts/call-action.sh --args-file assets/test-verify-email-draft-cycle.json --pretty +``` + +2. Find the new approval id from `pending_compact`. +3. Approve with the host bridge: + +```bash +python3 scripts/resolve-approval-with-gog.py --id --decision approve +``` + +4. Re-run `approval_queue_list` and confirm the matching history item shows: + - `execution_state = "executed"` + - `result_refs.draft_id` populated +5. Cleanup by queueing `assets/test-delete-email-draft.json` with the returned draft id and approving that item. + +### Calendar event queue → approve → verify → cleanup + +1. Queue the canned payload: + +```bash +scripts/call-action.sh --args-file assets/test-verify-calendar-event-cycle.json --pretty +``` + +2. Approve with the host bridge: + +```bash +python3 scripts/resolve-approval-with-gog.py --id --decision approve +``` + +3. Re-run `approval_queue_list` and confirm the matching history item shows: + - `execution_state = "executed"` + - `result_refs.event_id` populated +4. Cleanup by queueing `assets/test-delete-calendar-event.json` with the returned `event_id` and approving that item. + ## Expected success examples ### send_notification_draft diff --git a/skills/n8n-webhook/references/payloads.md b/skills/n8n-webhook/references/payloads.md index 3fc77eb..d550d71 100644 --- a/skills/n8n-webhook/references/payloads.md +++ b/skills/n8n-webhook/references/payloads.md @@ -48,6 +48,22 @@ Recommended request shape: } ``` +## Approval defaults by family + +- notification family + - `send_notification_draft` + - `approval.family = "notification"` + - `approval.required = true` + - `approval.mutation_level = "high"` +- Gmail family + - read-only: `list_email_drafts` → `approval.family = "gmail"`, `approval.mutation_level = "low"` + - mutating: `send_email_draft`, `delete_email_draft`, `send_gmail_draft` / `send_approved_email` → `approval.family = "gmail"`, `approval.mutation_level = "high"` +- Calendar family + - read-only: `list_upcoming_events` → `approval.family = "calendar"`, `approval.mutation_level = "low"` + - mutating: `create_calendar_event`, `update_calendar_event`, `delete_calendar_event` → `approval.family = "calendar"`, `approval.mutation_level = "high"` +- manual/generic approvals + - `approval_queue_add` leaves side effects to the operator; there is no automatic host executor for arbitrary manual kinds + ## Live actions in the shipped workflow asset ### `append_log` @@ -362,6 +378,9 @@ Request: Purpose: - inspect pending approval items - optionally include recent resolved history +- returns both raw entries and compact operator-friendly summaries at: + - `result.pending_compact` + - `result.history_compact` ### `approval_queue_resolve` @@ -405,6 +424,11 @@ Request: Purpose: - patch a resolved history item with host-side execution metadata after a real executor runs outside n8n - intended for bridges such as `gog`-backed Gmail/Calendar execution +- compact execution reporting should populate or expose: + - `execution.summary` + - `execution.result_refs` + - `item.operator.summary_line` + - `item.operator.execution_state` ### `fetch_and_normalize_url`