Files
swarm-zap/memory/2026-03-12.md

22 KiB

2026-03-12

n8n local documentation fix

  • Documented the local n8n-agent service in TOOLS.md after 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-ping webhook path tested end-to-end
  • 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-webhook for authenticated webhook-first n8n integration, including scripts/call-webhook.sh, scripts/call-action.sh, scripts/validate-workflow.py, an importable assets/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-action workflow intentionally leaves Webhook authentication unset in export JSON; after import, bind local n8n Header Auth credentials manually using x-openclaw-secret so 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-action via the n8n API.
  • First live implementation matched the original asset shape (Webhook -> Set -> Switch -> Respond) but failed at runtime: executions errored in the normalize-request Set node with invalid syntax on 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-action workflow 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_log returned 200 with normalized JSON success payload
    • notify returned 200 with normalized JSON success payload
    • unknown action returned 400 with { 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:
    • notify was successfully wired to the existing Telegram + Discord credentials and verified live multiple times.
    • append_log hit two dead ends before settling on the clean solution:
      1. Execute Command node was unavailable in this n8n build (Unrecognized node type: n8n-nodes-base.executeCommand).
      2. Read/Write Files from Disk was available, but candidate paths were either missing or not writable in this container/runtime.
    • Final fix: switched append_log to use n8n workflow static data ($getWorkflowStaticData('global')) under key actionLog, capped to the latest 200 entries.
    • Verified persisted state via the n8n API: staticData.global.actionLog contains the live test record for request live-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_logs to the live openclaw-action workflow and local n8n-webhook skill.
    • get_logs reads from workflow static data key actionLog
    • default limit 20, clamped to 1..50, newest-first
    • verified live with request live-getlogs-001 returning the seed record from live-log-004
  • Re-verified the three live actions together after the update:
    • append_log → success
    • get_logs → success
    • notify → 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-webhook router asset beyond the original live trio (append_log, get_logs, notify) to add:
    • send_email_draft
    • create_calendar_event
    • approval_queue_add
    • approval_queue_list
    • approval_queue_resolve
    • fetch_and_normalize_url
    • inbound_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-action workflow in place.
  • Live verification of the expanded action set after deployment:
    • append_log200
    • get_logs200
    • send_email_draft200 (approval-queued)
    • create_calendar_event200 (approval-queued)
    • approval_queue_add200
    • approval_queue_list200
    • approval_queue_resolve200
    • inbound_event_filter200
    • notify200
    • unknown action → 400 with unknown_action
  • fetch_and_normalize_url initially failed in the Code node because global fetch was 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_url to n8n's runtime helper this.helpers.httpRequest, which worked. Added optional arg skip_ssl_certificate_validation: true for environments where the container CA bundle is insufficient.
  • Verified fetch_and_normalize_url live with:
    • local HTTP URL http://192.168.153.113:18808/healthz → success
    • https://example.com with skip_ssl_certificate_validation: true → success
  • Cleanup: resolved the temporary verification approval items so approvalQueue ended 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, and Header 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 existing notify path and sends through Telegram + Discord
  • Verified live end-to-end on 2026-03-12:
    • send_notification_draft returned 200 and produced pending id approval-mmnr8pyq-tjxiqkps
    • approving that item via approval_queue_resolve returned executed: true and executed_action: "notify"
    • approval_queue_list showed pending_count: 0 afterward 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-TTY gog calls fail unless GOG_KEYRING_PASSWORD is present, because the current gog file keyring backend cannot prompt in automation. However, gog --dry-run for 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_draftgog gmail drafts create
      • calendar_eventgog calendar create
  • Expanded the live openclaw-action workflow with new action approval_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_draft approval item and one calendar_event item
    • resolved both via the new host bridge with --dry-run
    • gog returned dry-run JSON for both operations without touching Google state
    • approvalHistory entries were updated in n8n with execution metadata:
      • email draft item id approval-mmnsx7iz-k26qb60cexecution.op = gmail.drafts.create, status = dry_run
      • calendar item id approval-mmnsx7ji-3rt7yd74execution.op = calendar.create, status = dry_run
  • Current practical next step for real Gmail/Calendar execution: provide GOG_KEYRING_PASSWORD to the runtime environment that will invoke the bridge script, or switch gog to 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.env with restrictive permissions (600)
    • updated resolve-approval-with-gog.py to 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_draft approval item in --dry-run mode and attaching execution metadata successfully without manually exporting GOG_ACCOUNT / GOG_KEYRING_PASSWORD
  • Real direct Google sanity checks succeeded after that:
    • created a Gmail draft to william.valentin.info@gmail.com with subject Test draft from zap
    • deleted the same draft successfully and verified removal via follow-up 404 notFound
  • Created top-level state file WIP.md to track the current Google Workspace + n8n integration plan, status, completed work, and next steps.
  • Updated memory/tasks.json so the overlapping Google Workspace / calendar / email tasks moved from open to in-progress and 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 through resolve-approval-with-gog.py, verified with gog gmail drafts get, and deleted with gog gmail drafts delete --force.
      • approval id: approval-mmnvjcak-qcuhbzqd
      • draft id: r348335896293726096
      • subject: [zap n8n e2e] Gmail draft test 20260312T194153Z
    • Calendar event flow (create_calendar_event): queued, approved through the same bridge, verified with gog calendar get primary <eventId>, and deleted with gog calendar delete primary <eventId> --force.
      • approval id: approval-mmnvjyo5-uezhcw84
      • event id: il3ojkfnsnq3uhlepvrmaklpq4
      • title: [zap n8n e2e] Calendar test 20260312T194222Z
  • Important command-shape notes captured from the live run:
    • gog calendar get and gog calendar delete expect <calendarId> <eventId> argument order.
    • gog gmail drafts delete required --force for 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.md as 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 discipline section to AGENTS.md
    • creating HANDOFF.md as the immediate baton-pass file for the next clean implementation session
    • updating WIP.md with a Next-session handoff section

Fresh clean-context re-run (implementation subagent)

  • Executed the requested fresh-session baton pass from HANDOFF.md + WIP.md and re-proved the two real approval-routed Google flows end-to-end through n8n + host gog bridge.
  • 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-input returned the draft payload with expected subject/body
    • cleanup: gog gmail drafts delete <draftId> --force returned { "deleted": true, ... }
  • 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-input returned the created event
    • cleanup: gog calendar delete primary <eventId> --force returned { "deleted": true, ... }
  • 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
  • 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-action workflow contract:
    • list_email_drafts
    • delete_email_draft
    • send_gmail_draft (plus alias send_approved_email)
  • Added explicit approval metadata in queued action responses (approval.policy, approval.required, approval.mutation_level) and set mutating Gmail actions to high.
  • Extended host bridge resolve-approval-with-gog.py with executor coverage for:
    • email_list_draftsgog gmail drafts list
    • email_draft_deletegog gmail drafts delete
    • email_draft_sendgog gmail drafts send
  • Verification evidence (local/targeted):
    • workflow structure + contract validator passed
    • route-action simulation request IDs:
      • verify-list-001
      • verify-delete-001
      • verify-send-001
      • verify-send-alias-001
    • simulation produced pending IDs:
      • approval-mmny879w-5sncgd98
      • approval-mmny879w-a353xg8q
      • approval-mmny879w-yvqzokpz
      • approval-mmny879w-md99hqxs
    • gog dry-run command checks for list/delete/send each exited 0.

Calendar pass 2 (fresh subagent implementation, locally verified)

  • Added to openclaw-action workflow contract:
    • list_upcoming_events
    • update_calendar_event
    • delete_calendar_event
  • Preserved explicit approval metadata/policy:
    • list_upcoming_eventsapproval.mutation_level = low
    • update_calendar_event / delete_calendar_eventapproval.mutation_level = high
  • Extended host bridge resolve-approval-with-gog.py with executor coverage for:
    • calendar_list_eventsgog calendar events
    • calendar_event_updategog calendar update
    • calendar_event_deletegog calendar delete
  • Added sample payloads:
    • skills/n8n-webhook/assets/test-list-upcoming-events.json
    • skills/n8n-webhook/assets/test-update-calendar-event.json
    • skills/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-run
      • 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.

Live deploy + smoke verification

  • Re-synced the active n8n workflow Jwi54VWMdlLqYnRo from the current openclaw-action.workflow.json asset 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 → ok
    • get_logs → ok
    • list_email_drafts → queued_for_approval
    • list_upcoming_events → queued_for_approval
    • approval_queue_list → ok with pending_compact + history_compact
    • fetch_and_normalize_url against local /healthz → ok / HTTP 200
    • unknown action → expected HTTP 400 / unknown_action
  • Smoke-created pending approvals were rejected/cleaned:
    • approval-mmnzm1ev-yjk46sd1
    • approval-mmnzm1gi-l7yszi92
    • approval-mmnzmw80-kb8szya2
    • approval-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_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.jsonverify-email-draft-cycle-001
    • skills/n8n-webhook/assets/test-verify-calendar-event-cycle.jsonverify-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

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.
  • Preserved principle: the action bus works best for discrete, approval-worthy, low-iteration operations (like send draft, create event).
  • Updated WIP.drive-docs-sheets.md with closed status and revisit criteria per surface.
  • Updated memory/tasks.json to close:
    • task-20260311-1908-calendar-access → done
    • task-20260311-1908-email-access → done
    • task-20260311-1914-google-workspace-access → done
  • Google Workspace + n8n integration WIP (WIP.md) is now complete with evidence recorded in memory.