13 KiB
13 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