22 KiB
22 KiB
2026-03-12
n8n local documentation fix
- Documented the local
n8n-agentservice inTOOLS.mdafter noticing it had been set up but not captured in workspace notes. - Recorded current known service details from prior host/runtime evidence:
- port
18808 -> 5678 - LAN/Tailscale URLs
- dedicated agent-oriented n8n instance
openclaw-pingwebhook path tested end-to-end
- port
- 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. - Finished local skill
skills/n8n-webhookfor authenticated webhook-first n8n integration, includingscripts/call-webhook.sh,scripts/call-action.sh,scripts/validate-workflow.py, an importableassets/openclaw-action.workflow.json, sample payloads, payload notes, and a successful package/validation run to/tmp/n8n-skill-dist/n8n-webhook.skill. - The shipped
openclaw-actionworkflow intentionally leaves Webhook authentication unset in export JSON; after import, bind local n8n Header Auth credentials manually usingx-openclaw-secretso secrets are not embedded in the skill asset. - Live n8n API access was confirmed and used on 2026-03-12 against
http://192.168.153.113:18808(public API + existing webhook credential available in the instance). - Created and activated live workflow
openclaw-actionvia the n8n API. - First live implementation matched the original asset shape (
Webhook -> Set -> Switch -> Respond) but failed at runtime: executions errored in thenormalize-requestSet node withinvalid syntaxon its expressions. - Fix: replaced the live router logic and shipped asset implementation with a simpler, working internal design:
Webhook -> Code -> Respond to Webhook, while preserving the external contract (append_log,notify, normalized JSON success/failure responses). - Important operational note: the workflow initially activated without a usable production route because the Webhook node lacked a
webhookId; adding one and re-publishing was necessary for proper webhook registration. - Current state before compaction: the live
openclaw-actionworkflow exists in n8n, is active, and has been updated to the simpler Code-node implementation; post-update live response testing was still in progress at compaction time. - After compaction, live verification succeeded against the production webhook:
append_logreturned200with normalized JSON success payloadnotifyreturned200with normalized JSON success payload- unknown action returned
400with{ code: "unknown_action" }
- The packaged skill artifact was refreshed after the router simplification at
/tmp/n8n-skill-dist/n8n-webhook.skill. - Follow-up implementation for real side effects:
notifywas successfully wired to the existing Telegram + Discord credentials and verified live multiple times.append_loghit two dead ends before settling on the clean solution:Execute Commandnode was unavailable in this n8n build (Unrecognized node type: n8n-nodes-base.executeCommand).Read/Write Files from Diskwas available, but candidate paths were either missing or not writable in this container/runtime.
- Final fix: switched
append_logto use n8n workflow static data ($getWorkflowStaticData('global')) under keyactionLog, capped to the latest 200 entries. - Verified persisted state via the n8n API:
staticData.global.actionLogcontains the live test record for requestlive-log-003. - Conclusion: for small recent operational breadcrumbs, workflow static data is the right sink here; MinIO is better reserved for later archival/rotation/export use cases rather than tiny per-event appends.
- Added action
get_logsto the liveopenclaw-actionworkflow and localn8n-webhookskill.get_logsreads from workflow static data keyactionLog- default limit
20, clamped to1..50, newest-first - verified live with request
live-getlogs-001returning the seed record fromlive-log-004
- Re-verified the three live actions together after the update:
append_log→ successget_logs→ successnotify→ success
- Refreshed packaged skill artifact again at
/tmp/n8n-skill-dist/n8n-webhook.skill. - Will clarified a standing operating preference: treat local n8n as an assistant tool to use proactively when appropriate, not as something needing separate approval each time.
- Extended the shipped
skills/n8n-webhookrouter asset beyond the original live trio (append_log,get_logs,notify) to add:send_email_draftcreate_calendar_eventapproval_queue_addapproval_queue_listapproval_queue_resolvefetch_and_normalize_urlinbound_event_filter
- Design choice for the new actions: keep the starter workflow immediately usable without new provider credentials by using n8n workflow static data for approval queue/history/event state, while leaving room to wire provider-backed email/calendar executors later.
- Updated local docs, validator, and sample payloads for the expanded action bus and re-ran local structural validation successfully.
- Live n8n re-import/update was not completed in this pass because the current session did not have a verified safe path into the already-running instance (no confirmed admin/browser path and no confirmed current webhook secret for live test calls).
- Follow-up in the next direct session: recovered the already-verified live n8n API path from the earlier session log and used it to deploy the expanded
openclaw-actionworkflow in place. - Live verification of the expanded action set after deployment:
append_log→200get_logs→200send_email_draft→200(approval-queued)create_calendar_event→200(approval-queued)approval_queue_add→200approval_queue_list→200approval_queue_resolve→200inbound_event_filter→200notify→200- unknown action →
400withunknown_action
fetch_and_normalize_urlinitially failed in the Code node because globalfetchwas unavailable; a second attempt using Node built-ins failed because module imports were disallowed in the n8n runtime.- Final fix for URL fetching: switched
fetch_and_normalize_urlto n8n's runtime helperthis.helpers.httpRequest, which worked. Added optional argskip_ssl_certificate_validation: truefor environments where the container CA bundle is insufficient. - Verified
fetch_and_normalize_urllive with:- local HTTP URL
http://192.168.153.113:18808/healthz→ success https://example.comwithskip_ssl_certificate_validation: true→ success
- local HTTP URL
- Cleanup: resolved the temporary verification approval items so
approvalQueueended empty after testing. - State check before attempting deeper executor work: the live n8n instance currently exposes only four credentials via the public API —
Discord Bot Auth,Telegram Bot (OpenClaw),OpenClaw Webhook Header, andHeader Auth account. No Gmail/Google Calendar credentials were present, so provider-backed email/calendar execution was intentionally not faked. - Implemented the first true approval-gated executor that matches currently available creds:
- new action
send_notification_draft - queues a pending notification in
approvalQueue - when approved via
approval_queue_resolve, it executes the existingnotifypath and sends through Telegram + Discord
- new action
- Verified live end-to-end on 2026-03-12:
send_notification_draftreturned200and produced pending idapproval-mmnr8pyq-tjxiqkps- approving that item via
approval_queue_resolvereturnedexecuted: trueandexecuted_action: "notify" approval_queue_listshowedpending_count: 0afterward and recorded the execution metadata in history
- Will explicitly reinforced a durable operating expectation: local n8n, including its live public API, should be treated as assistant-owned tooling. If the correct path is the n8n API, use it directly instead of re-asking for permission or acting blocked.
- After Google Workspace auth was completed with
gog, headless testing showed an important automation constraint: real non-TTYgogcalls fail unlessGOG_KEYRING_PASSWORDis present, because the currentgogfile keyring backend cannot prompt in automation. However,gog --dry-runfor Gmail draft creation and Calendar event creation works without unlocking the keyring, which made it possible to fully validate executor plumbing safely. - Implemented a host-side bridge script at
skills/n8n-webhook/scripts/resolve-approval-with-gog.py.- flow: resolve approval in n8n → execute supported kinds on host via
gog→ write execution metadata back into n8n history - supported host-executed kinds:
email_draft→gog gmail drafts createcalendar_event→gog calendar create
- flow: resolve approval in n8n → execute supported kinds on host via
- Expanded the live
openclaw-actionworkflow with new actionapproval_history_attach_execution, allowing host-side executors to patch resolved history entries with execution status/details. - Live dry-run verification on 2026-03-12 succeeded end-to-end:
- queued one
email_draftapproval item and onecalendar_eventitem - resolved both via the new host bridge with
--dry-run gogreturned dry-run JSON for both operations without touching Google stateapprovalHistoryentries were updated in n8n with execution metadata:- email draft item id
approval-mmnsx7iz-k26qb60c→execution.op = gmail.drafts.create,status = dry_run - calendar item id
approval-mmnsx7ji-3rt7yd74→execution.op = calendar.create,status = dry_run
- email draft item id
- queued one
- Current practical next step for real Gmail/Calendar execution: provide
GOG_KEYRING_PASSWORDto the runtime environment that will invoke the bridge script, or switchgogto a keyring backend that supports unattended access on this host. - Follow-up completion on 2026-03-12:
- stored local-only Gog automation env in
/home/openclaw/.openclaw/credentials/gog.envwith restrictive permissions (600) - updated
resolve-approval-with-gog.pyto auto-load that file when present - verified non-interactive headless Gmail access works using the stored env (successful
gog gmail search ... --json --no-input) - verified the bridge itself auto-loads the env file by resolving a fresh
email_draftapproval item in--dry-runmode and attaching execution metadata successfully without manually exportingGOG_ACCOUNT/GOG_KEYRING_PASSWORD
- stored local-only Gog automation env in
- Real direct Google sanity checks succeeded after that:
- created a Gmail draft to
william.valentin.info@gmail.comwith subjectTest draft from zap - deleted the same draft successfully and verified removal via follow-up
404 notFound
- created a Gmail draft to
- Created top-level state file
WIP.mdto track the current Google Workspace + n8n integration plan, status, completed work, and next steps. - Updated
memory/tasks.jsonso the overlapping Google Workspace / calendar / email tasks moved fromopentoin-progressand now point at the current WIP file. - Will explicitly noted a durable capability reminder: zap also has access to Will's own Gitea repo on the LAN and can use it when repo-backed tracking/sync is useful.
- Real end-to-end Google execution via n8n approval + gog bridge was completed (non-dry-run) for both target flows:
- Gmail draft flow (
send_email_draft): queued, approved throughresolve-approval-with-gog.py, verified withgog gmail drafts get, and deleted withgog gmail drafts delete --force.- approval id:
approval-mmnvjcak-qcuhbzqd - draft id:
r348335896293726096 - subject:
[zap n8n e2e] Gmail draft test 20260312T194153Z
- approval id:
- Calendar event flow (
create_calendar_event): queued, approved through the same bridge, verified withgog calendar get primary <eventId>, and deleted withgog calendar delete primary <eventId> --force.- approval id:
approval-mmnvjyo5-uezhcw84 - event id:
il3ojkfnsnq3uhlepvrmaklpq4 - title:
[zap n8n e2e] Calendar test 20260312T194222Z
- approval id:
- Gmail draft flow (
- Important command-shape notes captured from the live run:
gog calendar getandgog calendar deleteexpect<calendarId> <eventId>argument order.gog gmail drafts deleterequired--forcefor non-interactive cleanup.
- Will also set a new operating preference for context use: for non-trivial implementation work, prepare file-based state/handoff (
WIP.md,HANDOFF.mdas needed), then start a fresh isolated implementation session/run instead of continuing inside a bloated main-session context window. - Implemented that preference locally by:
- adding a
Fresh-session implementation disciplinesection toAGENTS.md - creating
HANDOFF.mdas the immediate baton-pass file for the next clean implementation session - updating
WIP.mdwith aNext-session handoffsection
- adding a
Fresh clean-context re-run (implementation subagent)
- Executed the requested fresh-session baton pass from
HANDOFF.md+WIP.mdand re-proved the two real approval-routed Google flows end-to-end through n8n + hostgogbridge. - Real Gmail draft flow (
send_email_draft) re-run:- approval id:
approval-mmnvn4t2-w2rjlwz2 - draft id:
r-3319106208870238577 - subject:
[zap n8n e2e] Gmail draft test 20260312T194450Z - verification:
gog gmail drafts get <draftId> --json --no-inputreturned the draft payload with expected subject/body - cleanup:
gog gmail drafts delete <draftId> --forcereturned{ "deleted": true, ... }
- approval id:
- Real Calendar event flow (
create_calendar_event) re-run:- approval id:
approval-mmnvn6i8-e9eq8gdf - event id:
m7prri8vk2opuo6loq3qgtvsv4 - title:
[zap n8n e2e] Calendar test 20260312T194450Z - verification:
gog calendar get primary <eventId> --json --no-inputreturned the created event - cleanup:
gog calendar delete primary <eventId> --forcereturned{ "deleted": true, ... }
- approval id:
- Refreshed baton/state files (
HANDOFF.md,WIP.md) to mark this fresh-session proof as complete and move next target to expanding Gmail/Calendar action coverage (list/update/delete flows + operator playbook).
Delegation tier policy update (fresh implementation run)
- Updated local delegation policy to use LiteLLM-targeted tiers:
- simple/light →
litellm/glm-4.7-flash - medium/default →
litellm/glm-5 - hardest/high-stakes →
litellm/gpt-4.5
- simple/light →
- Applied consistently in:
skills/delegation-router/SKILL.md(tier map + spawn examples)AGENTS.md(workspace routing guidance section)USER.md(user preference line)MEMORY.md(durable preference line)
Gmail pass 1 (fresh subagent implementation)
- Added to
openclaw-actionworkflow contract:list_email_draftsdelete_email_draftsend_gmail_draft(plus aliassend_approved_email)
- Added explicit approval metadata in queued action responses (
approval.policy,approval.required,approval.mutation_level) and set mutating Gmail actions tohigh. - Extended host bridge
resolve-approval-with-gog.pywith executor coverage for:email_list_drafts→gog gmail drafts listemail_draft_delete→gog gmail drafts deleteemail_draft_send→gog gmail drafts send
- Verification evidence (local/targeted):
- workflow structure + contract validator passed
- route-action simulation request IDs:
verify-list-001verify-delete-001verify-send-001verify-send-alias-001
- simulation produced pending IDs:
approval-mmny879w-5sncgd98approval-mmny879w-a353xg8qapproval-mmny879w-yvqzokpzapproval-mmny879w-md99hqxs
gogdry-run command checks for list/delete/send each exited0.
Calendar pass 2 (fresh subagent implementation, locally verified)
- Added to
openclaw-actionworkflow contract:list_upcoming_eventsupdate_calendar_eventdelete_calendar_event
- Preserved explicit approval metadata/policy:
list_upcoming_events→approval.mutation_level = lowupdate_calendar_event/delete_calendar_event→approval.mutation_level = high
- Extended host bridge
resolve-approval-with-gog.pywith executor coverage for:calendar_list_events→gog calendar eventscalendar_event_update→gog calendar updatecalendar_event_delete→gog calendar delete
- Added sample payloads:
skills/n8n-webhook/assets/test-list-upcoming-events.jsonskills/n8n-webhook/assets/test-update-calendar-event.jsonskills/n8n-webhook/assets/test-delete-calendar-event.json
- Verification evidence (local/targeted):
- workflow structure + contract validator passed after the calendar additions
- workflow asset inspection confirmed the three new router actions are present
- bridge command-builder checks from shipped payloads produced:
gog calendar events primary --account will@example.com --json --no-input --max 10 --days 7 --query zap --dry-rungog 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-rungog 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.pypassed.
Live deploy + smoke verification
- Re-synced the active n8n workflow
Jwi54VWMdlLqYnRofrom the currentopenclaw-action.workflow.jsonasset while preserving the bound webhook credential + webhook id. - First sync exposed that the live workflow had still been on the older minimal router; re-synced again from the current full asset and re-activated successfully.
- Safe production-webhook smoke calls succeeded:
append_log→ okget_logs→ oklist_email_drafts→ queued_for_approvallist_upcoming_events→ queued_for_approvalapproval_queue_list→ ok withpending_compact+history_compactfetch_and_normalize_urlagainst local/healthz→ ok / HTTP 200- unknown action → expected HTTP 400 /
unknown_action
- Smoke-created pending approvals were rejected/cleaned:
approval-mmnzm1ev-yjk46sd1approval-mmnzm1gi-l7yszi92approval-mmnzmw80-kb8szya2approval-mmnzmw9w-c25hlml4
- Remaining pending items after cleanup were older pre-existing queue items and were intentionally left alone.
Subagent monitoring thresholds
- Added an explicit operating rule for fresh implementation runs:
- first routine check at ~5 minutes if still running
- inspect child history at ~10 minutes
- narrow pass feels suspiciously long at ~12 minutes and should be actively intervened by ~15 minutes absent crisp progress
- medium bounded pass feels suspiciously long at ~20 minutes and should be actively intervened by ~25 minutes absent crisp progress
- Also recorded the fallback rule: if the run is looping, not updating
WIP.md, or returns an unusable result, finish the pass directly in the main session after one inspection.
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_previewoperator.summary_lineoperator.execution_stateoperator.result_refs- compact list surfaces:
pending_compact,history_compact,item_compact
- Extended the host bridge so attached execution metadata now includes:
execution.summaryexecution.result_refs
- Added recurring verification payloads with stable proof IDs:
skills/n8n-webhook/assets/test-verify-email-draft-cycle.json→verify-email-draft-cycle-001skills/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.createsample result produceddraft_id = r-proof-draft-123 - bridge helper proof:
calendar.createsample result producedevent_id = evt-proof-456,calendar = primary - workflow asset string checks confirmed presence of
pending_compact,history_compact,summary_line,result_refs,default_mode, andapproval.family
Drive/Docs/Sheets evaluation (main session)
- Hit GPT-5.4 rate limit during attempted subagent work; continued evaluation in main session with GLM 5.
- Completed decision on expanding Google Workspace action bus beyond Gmail + Calendar into Drive / Docs / Sheets.
- Decision: NO for all three surfaces — defer for now.
- Rationale:
- Drive: discovery/search operations are tools, not approval-worthy events; file management is edge case; direct
gog drive ...usage is simpler. - Docs: editing is inherently iterative (see, tweak, see again); document work belongs in focused tool flows, not a one-shot queue.
- Sheets: strongest candidate (structured writes map well to approval), but without a concrete use case, this is premature optimization.
- Drive: discovery/search operations are tools, not approval-worthy events; file management is edge case; direct
- Preserved principle: the action bus works best for discrete, approval-worthy, low-iteration operations (like send draft, create event).
- Updated
WIP.drive-docs-sheets.mdwith closed status and revisit criteria per surface. - Updated
memory/tasks.jsonto close:task-20260311-1908-calendar-access→ donetask-20260311-1908-email-access→ donetask-20260311-1914-google-workspace-access→ done
- Google Workspace + n8n integration WIP (WIP.md) is now complete with evidence recorded in memory.