@caoscompanybr/merlin 3.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (762) hide show
  1. package/.claude/CLAUDE.md +216 -0
  2. package/.claude/hooks/README-license-gate.md +45 -0
  3. package/.claude/hooks/auto-summarize.js +47 -0
  4. package/.claude/hooks/context-monitor.js +60 -0
  5. package/.claude/hooks/doc-sync.js +111 -0
  6. package/.claude/hooks/license-gate.cjs +59 -0
  7. package/.claude/hooks/session-reset.js +27 -0
  8. package/.claude/hooks/thoughts-indexer.js +80 -0
  9. package/.claude/rules/merlin-constitution.md +27 -0
  10. package/.merlin-core/commands/README.md +19 -0
  11. package/.merlin-core/commands/founder-mode.md +51 -0
  12. package/.merlin-core/commands/git/commit.md +35 -0
  13. package/.merlin-core/commands/git/describe-pr.md +43 -0
  14. package/.merlin-core/commands/git/safe-commit.md +182 -0
  15. package/.merlin-core/commands/implementation/implement-plan.md +129 -0
  16. package/.merlin-core/commands/implementation/oneshot.md +63 -0
  17. package/.merlin-core/commands/implementation/tdd.md +152 -0
  18. package/.merlin-core/commands/planning/create-plan.md +184 -0
  19. package/.merlin-core/commands/planning/iterate-plan.md +45 -0
  20. package/.merlin-core/commands/planning/validate-plan.md +48 -0
  21. package/.merlin-core/commands/research/analyze-issue.md +155 -0
  22. package/.merlin-core/commands/research/research-codebase.md +157 -0
  23. package/.merlin-core/commands/review/adversarial-review.md +112 -0
  24. package/.merlin-core/commands/review/check.md +91 -0
  25. package/.merlin-core/commands/review/debug.md +135 -0
  26. package/.merlin-core/commands/review/doubts.md +178 -0
  27. package/.merlin-core/commands/review/engineering-audit.md +87 -0
  28. package/.merlin-core/commands/review/local-review.md +48 -0
  29. package/.merlin-core/commands/review/verify-goals.md +83 -0
  30. package/.merlin-core/commands/session/capture-feedback.md +74 -0
  31. package/.merlin-core/commands/session/capture-learning.md +155 -0
  32. package/.merlin-core/commands/session/check-objectives.md +85 -0
  33. package/.merlin-core/commands/session/conclude.md +125 -0
  34. package/.merlin-core/commands/session/create-handoff.md +88 -0
  35. package/.merlin-core/commands/session/create-objective.md +111 -0
  36. package/.merlin-core/commands/session/create-process.md +105 -0
  37. package/.merlin-core/commands/session/create-reminder.md +86 -0
  38. package/.merlin-core/commands/session/fast-start.md +261 -0
  39. package/.merlin-core/commands/session/recall-learnings.md +79 -0
  40. package/.merlin-core/commands/session/recall-processes.md +74 -0
  41. package/.merlin-core/commands/session/resume-handoff.md +51 -0
  42. package/.merlin-core/commands/session/run-process.md +53 -0
  43. package/.merlin-core/commands/special/beauty.md +89 -0
  44. package/.merlin-core/commands/special/common-ground.md +114 -0
  45. package/.merlin-core/commands/special/elicit.md +98 -0
  46. package/.merlin-core/commands/special/party.md +66 -0
  47. package/.merlin-core/commands/special/scrape.md +78 -0
  48. package/.merlin-core/commands/special/skill-audit.md +128 -0
  49. package/.merlin-core/commands/special/start-here.md +132 -0
  50. package/.merlin-core/constitution.md +442 -0
  51. package/.merlin-core/core/README.md +19 -0
  52. package/.merlin-core/core/alkimia/README.md +20 -0
  53. package/.merlin-core/core/alkimia/context/context-tracker.js +209 -0
  54. package/.merlin-core/core/alkimia/domain/domain-loader.js +215 -0
  55. package/.merlin-core/core/alkimia/engine.js +284 -0
  56. package/.merlin-core/core/alkimia/layers/l0-constitution.js +47 -0
  57. package/.merlin-core/core/alkimia/layers/l1-global.js +58 -0
  58. package/.merlin-core/core/alkimia/layers/l2-agent.js +58 -0
  59. package/.merlin-core/core/alkimia/layers/l3-workflow.js +54 -0
  60. package/.merlin-core/core/alkimia/layers/l4-task.js +45 -0
  61. package/.merlin-core/core/alkimia/layers/l5-squad.js +161 -0
  62. package/.merlin-core/core/alkimia/layers/l6-skill.js +520 -0
  63. package/.merlin-core/core/alkimia/layers/l7-star-command.js +87 -0
  64. package/.merlin-core/core/alkimia/layers/layer-processor.js +78 -0
  65. package/.merlin-core/core/alkimia/mandate.js +46 -0
  66. package/.merlin-core/core/alkimia/memory/doc-sync.js +201 -0
  67. package/.merlin-core/core/alkimia/memory/document-sharder.js +272 -0
  68. package/.merlin-core/core/alkimia/memory/git-history-retriever.js +225 -0
  69. package/.merlin-core/core/alkimia/memory/memory-bridge.js +97 -0
  70. package/.merlin-core/core/alkimia/memory/session-analyzer.js +400 -0
  71. package/.merlin-core/core/alkimia/memory/thoughts-indexer.js +477 -0
  72. package/.merlin-core/core/alkimia/memory/thoughts-provider.js +603 -0
  73. package/.merlin-core/core/alkimia/output/formatter.js +464 -0
  74. package/.merlin-core/core/alkimia/security/content-sanitizer.js +140 -0
  75. package/.merlin-core/core/alkimia/skill-importer.js +440 -0
  76. package/.merlin-core/core/alkimia/squads/default/.synapse/manifest +17 -0
  77. package/.merlin-core/core/alkimia/utils/frontmatter.js +321 -0
  78. package/.merlin-core/core/alkimia/utils/tokens.js +24 -0
  79. package/.merlin-core/core/approval/README.md +16 -0
  80. package/.merlin-core/core/approval/approval-engine.js +380 -0
  81. package/.merlin-core/core/approval/channels/cli-channel.js +50 -0
  82. package/.merlin-core/core/config/README.md +17 -0
  83. package/.merlin-core/core/config/config-cache.js +182 -0
  84. package/.merlin-core/core/config/config-loader.js +279 -0
  85. package/.merlin-core/core/config/config-resolver.js +411 -0
  86. package/.merlin-core/core/config/env-interpolator.js +123 -0
  87. package/.merlin-core/core/config/merge-utils.js +102 -0
  88. package/.merlin-core/core/config/schemas/core-config.schema.json +41 -0
  89. package/.merlin-core/core/config/schemas/framework-config.schema.json +24 -0
  90. package/.merlin-core/core/config/schemas/local-config.schema.json +23 -0
  91. package/.merlin-core/core/config/schemas/project-config.schema.json +189 -0
  92. package/.merlin-core/core/docs-consistency.js +140 -0
  93. package/.merlin-core/core/events/event-bus.js +344 -0
  94. package/.merlin-core/core/events/hook-handler.js +419 -0
  95. package/.merlin-core/core/execution/README.md +17 -0
  96. package/.merlin-core/core/execution/attempt-journal.js +380 -0
  97. package/.merlin-core/core/execution/autonomous-build-loop.js +637 -0
  98. package/.merlin-core/core/execution/build-orchestrator.js +296 -0
  99. package/.merlin-core/core/execution/build-state-manager.js +196 -0
  100. package/.merlin-core/core/execution/context-injector.js +204 -0
  101. package/.merlin-core/core/execution/cron-engine.js +247 -0
  102. package/.merlin-core/core/execution/cron-expression.js +148 -0
  103. package/.merlin-core/core/execution/env-preflight.js +423 -0
  104. package/.merlin-core/core/execution/guardrail-engine.js +745 -0
  105. package/.merlin-core/core/execution/heartbeat-engine.js +198 -0
  106. package/.merlin-core/core/execution/model-router.js +282 -0
  107. package/.merlin-core/core/execution/parallel-executor.js +378 -0
  108. package/.merlin-core/core/execution/parallel-monitor.js +201 -0
  109. package/.merlin-core/core/execution/party-session.js +311 -0
  110. package/.merlin-core/core/execution/rate-limit-manager.js +152 -0
  111. package/.merlin-core/core/execution/result-aggregator.js +215 -0
  112. package/.merlin-core/core/execution/semantic-merge-engine.js +320 -0
  113. package/.merlin-core/core/execution/subagent-dispatcher.js +721 -0
  114. package/.merlin-core/core/execution/success-verifier.js +227 -0
  115. package/.merlin-core/core/execution/task-metadata.js +105 -0
  116. package/.merlin-core/core/execution/team-executor.js +195 -0
  117. package/.merlin-core/core/execution/two-tier-editor.js +290 -0
  118. package/.merlin-core/core/execution/version-snapshot.js +294 -0
  119. package/.merlin-core/core/execution/wave-executor.js +224 -0
  120. package/.merlin-core/core/health-check/health-engine.js +415 -0
  121. package/.merlin-core/core/licensing/activation.js +281 -0
  122. package/.merlin-core/core/licensing/crc.js +103 -0
  123. package/.merlin-core/core/licensing/entitlement.js +99 -0
  124. package/.merlin-core/core/licensing/fingerprint.js +104 -0
  125. package/.merlin-core/core/licensing/gate.js +133 -0
  126. package/.merlin-core/core/licensing/hmac.js +42 -0
  127. package/.merlin-core/core/licensing/key.js +144 -0
  128. package/.merlin-core/core/licensing/license.js +212 -0
  129. package/.merlin-core/core/mcp/README.md +16 -0
  130. package/.merlin-core/core/mcp/browser-capability.js +191 -0
  131. package/.merlin-core/core/mcp/capability-mapper.js +92 -0
  132. package/.merlin-core/core/mcp/mcp-connector.js +278 -0
  133. package/.merlin-core/core/mcp/mcp-registry.js +101 -0
  134. package/.merlin-core/core/orchestration/README.md +17 -0
  135. package/.merlin-core/core/orchestration/agent-invoker.js +456 -0
  136. package/.merlin-core/core/orchestration/condition-evaluator.js +250 -0
  137. package/.merlin-core/core/orchestration/decision-tree.js +192 -0
  138. package/.merlin-core/core/orchestration/executor-assignment.js +372 -0
  139. package/.merlin-core/core/orchestration/gate-evaluator.js +653 -0
  140. package/.merlin-core/core/orchestration/intent-classifier.js +579 -0
  141. package/.merlin-core/core/orchestration/lock-manager.js +308 -0
  142. package/.merlin-core/core/orchestration/master-orchestrator.js +363 -0
  143. package/.merlin-core/core/orchestration/phase-tool-masks.js +194 -0
  144. package/.merlin-core/core/orchestration/recovery-handler.js +402 -0
  145. package/.merlin-core/core/orchestration/reflect-checkpoint.js +431 -0
  146. package/.merlin-core/core/orchestration/session-state.js +430 -0
  147. package/.merlin-core/core/orchestration/skill-dispatcher.js +255 -0
  148. package/.merlin-core/core/orchestration/step-loader.js +226 -0
  149. package/.merlin-core/core/orchestration/workflow-executor.js +864 -0
  150. package/.merlin-core/core/process/executor.js +231 -0
  151. package/.merlin-core/core/process/process-file.js +50 -0
  152. package/.merlin-core/core/process/secret-scan.js +86 -0
  153. package/.merlin-core/core/process/signature.js +77 -0
  154. package/.merlin-core/core/quality-gates/README.md +17 -0
  155. package/.merlin-core/core/quality-gates/layer1-precommit.js +110 -0
  156. package/.merlin-core/core/quality-gates/layer2-pr-automation.js +116 -0
  157. package/.merlin-core/core/quality-gates/layer3-human-review.js +133 -0
  158. package/.merlin-core/core/registry/service-registry.js +140 -0
  159. package/.merlin-core/core-config.yaml +159 -0
  160. package/.merlin-core/development/README.md +17 -0
  161. package/.merlin-core/development/agents/README.md +16 -0
  162. package/.merlin-core/development/agents/analyst.md +214 -0
  163. package/.merlin-core/development/agents/architect.md +166 -0
  164. package/.merlin-core/development/agents/data-engineer.md +154 -0
  165. package/.merlin-core/development/agents/dev.md +203 -0
  166. package/.merlin-core/development/agents/devops.md +236 -0
  167. package/.merlin-core/development/agents/grimorio.md +125 -0
  168. package/.merlin-core/development/agents/merlin-master.md +173 -0
  169. package/.merlin-core/development/agents/meta.md +190 -0
  170. package/.merlin-core/development/agents/pm.md +145 -0
  171. package/.merlin-core/development/agents/po.md +172 -0
  172. package/.merlin-core/development/agents/qa.md +275 -0
  173. package/.merlin-core/development/agents/researcher.md +218 -0
  174. package/.merlin-core/development/agents/scout.md +179 -0
  175. package/.merlin-core/development/agents/sm.md +148 -0
  176. package/.merlin-core/development/agents/ux.md +169 -0
  177. package/.merlin-core/development/agents/web-researcher.md +203 -0
  178. package/.merlin-core/development/checklists/adversarial-review-checklist.md +70 -0
  179. package/.merlin-core/development/checklists/operations-ci-checklist.md +40 -0
  180. package/.merlin-core/development/checklists/operations-deploy-checklist.md +54 -0
  181. package/.merlin-core/development/checklists/operations-publish-checklist.md +47 -0
  182. package/.merlin-core/development/checklists/source-verification-checklist.md +38 -0
  183. package/.merlin-core/development/templates/HEARTBEAT-template.md +46 -0
  184. package/.merlin-core/development/templates/ears-requirements-template.md +93 -0
  185. package/.merlin-core/development/templates/handoff-template.md +50 -0
  186. package/.merlin-core/development/templates/prd-template.md +62 -0
  187. package/.merlin-core/development/templates/research-template.md +53 -0
  188. package/.merlin-core/development/templates/spec-template.md +84 -0
  189. package/.merlin-core/development/workflows/brownfield-discovery.yaml +166 -0
  190. package/.merlin-core/development/workflows/brownfield-service.yaml +52 -0
  191. package/.merlin-core/development/workflows/development-cycle.yaml +57 -0
  192. package/.merlin-core/development/workflows/epic-orchestration.yaml +47 -0
  193. package/.merlin-core/development/workflows/folloni-funnel.yaml +177 -0
  194. package/.merlin-core/development/workflows/greenfield-fullstack.yaml +167 -0
  195. package/.merlin-core/development/workflows/greenfield-service.yaml +56 -0
  196. package/.merlin-core/development/workflows/qa-loop.yaml +115 -0
  197. package/.merlin-core/development/workflows/spec-pipeline.yaml +185 -0
  198. package/.merlin-core/development/workflows/steps/folloni-01-research.yaml +35 -0
  199. package/.merlin-core/development/workflows/steps/folloni-02-architecture.yaml +41 -0
  200. package/.merlin-core/development/workflows/steps/folloni-03-implementation.yaml +52 -0
  201. package/.merlin-core/development/workflows/story-development-cycle.yaml +67 -0
  202. package/.merlin-core/docs/GUIDE.md +413 -0
  203. package/.merlin-core/docs/merlin-commands-guide-pt.md +183 -0
  204. package/.merlin-core/framework-config.yaml +148 -0
  205. package/.merlin-core/hooks/README.md +16 -0
  206. package/.merlin-core/hooks/precompact-memory-flush.js +69 -0
  207. package/.merlin-core/hooks/pretooluse-remote-approve.js +113 -0
  208. package/.merlin-core/hooks/spikes/spike-b-hook.js +70 -0
  209. package/.merlin-core/hooks/spikes/spike-b-stub.js +70 -0
  210. package/.merlin-core/index.js +91 -0
  211. package/.merlin-core/local-config.yaml.template +31 -0
  212. package/.merlin-core/mcp-servers/lsp-bridge/index.js +397 -0
  213. package/.merlin-core/modules/scraping/module.json +23 -0
  214. package/.merlin-core/project-config.yaml +89 -0
  215. package/.merlin-core/schemas/README.md +18 -0
  216. package/.merlin-core/schemas/agent-hook-schema.json +152 -0
  217. package/.merlin-core/schemas/agent-schema.json +31 -0
  218. package/.merlin-core/schemas/command-schema.json +18 -0
  219. package/.merlin-core/schemas/feedback-schema.json +36 -0
  220. package/.merlin-core/schemas/handoff-schema.json +19 -0
  221. package/.merlin-core/schemas/learning-schema.json +51 -0
  222. package/.merlin-core/schemas/module.schema.json +124 -0
  223. package/.merlin-core/schemas/must-haves-schema.json +95 -0
  224. package/.merlin-core/schemas/objective-schema.json +23 -0
  225. package/.merlin-core/schemas/plan-schema.json +20 -0
  226. package/.merlin-core/schemas/process-schema.json +82 -0
  227. package/.merlin-core/schemas/reminder-schema.json +20 -0
  228. package/.merlin-core/schemas/skill-eval-schema.json +92 -0
  229. package/.merlin-core/schemas/skill-schema.json +77 -0
  230. package/.merlin-core/schemas/workflow-schema.json +38 -0
  231. package/.merlin-core/skills/README.md +16 -0
  232. package/.merlin-core/skills/domain/azure-cloud/SKILL.md +211 -0
  233. package/.merlin-core/skills/domain/azure-cloud/references/appinsights-instrumentation.md +63 -0
  234. package/.merlin-core/skills/domain/azure-cloud/references/azure-compliance.md +99 -0
  235. package/.merlin-core/skills/domain/azure-cloud/references/azure-cost-optimization.md +419 -0
  236. package/.merlin-core/skills/domain/azure-cloud/references/azure-deploy.md +82 -0
  237. package/.merlin-core/skills/domain/azure-cloud/references/azure-diagnostics.md +130 -0
  238. package/.merlin-core/skills/domain/azure-cloud/references/azure-prepare.md +134 -0
  239. package/.merlin-core/skills/domain/azure-cloud/references/azure-quotas.md +290 -0
  240. package/.merlin-core/skills/domain/azure-cloud/references/azure-rbac.md +11 -0
  241. package/.merlin-core/skills/domain/azure-cloud/references/azure-resource-lookup.md +97 -0
  242. package/.merlin-core/skills/domain/azure-cloud/references/azure-resource-visualizer.md +178 -0
  243. package/.merlin-core/skills/domain/azure-cloud/references/azure-storage.md +91 -0
  244. package/.merlin-core/skills/domain/azure-cloud/references/azure-validate.md +58 -0
  245. package/.merlin-core/skills/domain/azure-cloud/references/entra-app-registration.md +192 -0
  246. package/.merlin-core/skills/domain/browser-automation/SKILL.md +311 -0
  247. package/.merlin-core/skills/domain/browser-automation/references/agent-browser-skill.md +632 -0
  248. package/.merlin-core/skills/domain/browser-automation/references/authentication.md +308 -0
  249. package/.merlin-core/skills/domain/browser-automation/references/commands.md +266 -0
  250. package/.merlin-core/skills/domain/browser-automation/references/profiling.md +120 -0
  251. package/.merlin-core/skills/domain/browser-automation/references/proxy-support.md +194 -0
  252. package/.merlin-core/skills/domain/browser-automation/references/session-management.md +194 -0
  253. package/.merlin-core/skills/domain/browser-automation/references/snapshot-refs.md +196 -0
  254. package/.merlin-core/skills/domain/browser-automation/references/video-recording.md +173 -0
  255. package/.merlin-core/skills/domain/browser-automation/templates/authenticated-session.sh +105 -0
  256. package/.merlin-core/skills/domain/browser-automation/templates/capture-workflow.sh +69 -0
  257. package/.merlin-core/skills/domain/browser-automation/templates/form-automation.sh +62 -0
  258. package/.merlin-core/skills/domain/digital-marketing/SKILL.md +292 -0
  259. package/.merlin-core/skills/domain/digital-marketing/references/content-strategy.md +320 -0
  260. package/.merlin-core/skills/domain/digital-marketing/references/copy-formats.md +298 -0
  261. package/.merlin-core/skills/domain/digital-marketing/references/copy-methodology.md +180 -0
  262. package/.merlin-core/skills/domain/digital-marketing/references/email-sequences.md +135 -0
  263. package/.merlin-core/skills/domain/digital-marketing/references/launch-strategy.md +213 -0
  264. package/.merlin-core/skills/domain/digital-marketing/references/pricing-strategy.md +160 -0
  265. package/.merlin-core/skills/domain/digital-marketing/references/programmatic-seo.md +237 -0
  266. package/.merlin-core/skills/domain/digital-marketing/references/revops-lifecycle.md +170 -0
  267. package/.merlin-core/skills/domain/digital-marketing/references/revops-operations.md +167 -0
  268. package/.merlin-core/skills/domain/digital-marketing/references/schema-markup.md +190 -0
  269. package/.merlin-core/skills/domain/digital-marketing/references/strategy-frameworks.md +324 -0
  270. package/.merlin-core/skills/domain/digital-marketing/references/traffic-management.md +350 -0
  271. package/.merlin-core/skills/domain/expo-native-ui/SKILL.md +348 -0
  272. package/.merlin-core/skills/domain/expo-native-ui/references/animations.md +220 -0
  273. package/.merlin-core/skills/domain/expo-native-ui/references/api-routes.md +361 -0
  274. package/.merlin-core/skills/domain/expo-native-ui/references/cicd-workflows.md +84 -0
  275. package/.merlin-core/skills/domain/expo-native-ui/references/controls.md +266 -0
  276. package/.merlin-core/skills/domain/expo-native-ui/references/data-fetching.md +553 -0
  277. package/.merlin-core/skills/domain/expo-native-ui/references/deployment-stores.md +1353 -0
  278. package/.merlin-core/skills/domain/expo-native-ui/references/deployment.md +183 -0
  279. package/.merlin-core/skills/domain/expo-native-ui/references/dev-client.md +166 -0
  280. package/.merlin-core/skills/domain/expo-native-ui/references/dom-components.md +410 -0
  281. package/.merlin-core/skills/domain/expo-native-ui/references/form-sheet.md +253 -0
  282. package/.merlin-core/skills/domain/expo-native-ui/references/gradients.md +117 -0
  283. package/.merlin-core/skills/domain/expo-native-ui/references/icons.md +218 -0
  284. package/.merlin-core/skills/domain/expo-native-ui/references/media.md +245 -0
  285. package/.merlin-core/skills/domain/expo-native-ui/references/platform-native.md +75 -0
  286. package/.merlin-core/skills/domain/expo-native-ui/references/route-structure.md +229 -0
  287. package/.merlin-core/skills/domain/expo-native-ui/references/search.md +249 -0
  288. package/.merlin-core/skills/domain/expo-native-ui/references/storage.md +121 -0
  289. package/.merlin-core/skills/domain/expo-native-ui/references/tabs.md +433 -0
  290. package/.merlin-core/skills/domain/expo-native-ui/references/tailwind-native.md +473 -0
  291. package/.merlin-core/skills/domain/expo-native-ui/references/toolbar-and-headers.md +284 -0
  292. package/.merlin-core/skills/domain/expo-native-ui/references/upgrading-guides.md +674 -0
  293. package/.merlin-core/skills/domain/expo-native-ui/references/upgrading.md +127 -0
  294. package/.merlin-core/skills/domain/expo-native-ui/references/visual-effects.md +199 -0
  295. package/.merlin-core/skills/domain/expo-native-ui/references/webgpu-three.md +605 -0
  296. package/.merlin-core/skills/domain/expo-native-ui/references/zoom-transitions.md +161 -0
  297. package/.merlin-core/skills/domain/marketing-ops/SKILL.md +117 -0
  298. package/.merlin-core/skills/domain/marketing-ops/references/_index.md +78 -0
  299. package/.merlin-core/skills/domain/marketing-ops/references/acquire/ad-creative/references/generative-tools.md +19 -0
  300. package/.merlin-core/skills/domain/marketing-ops/references/acquire/ad-creative/references/platform-specs.md +19 -0
  301. package/.merlin-core/skills/domain/marketing-ops/references/acquire/ad-creative.md +251 -0
  302. package/.merlin-core/skills/domain/marketing-ops/references/acquire/ads/references/ad-copy-templates.md +19 -0
  303. package/.merlin-core/skills/domain/marketing-ops/references/acquire/ads/references/audience-targeting.md +19 -0
  304. package/.merlin-core/skills/domain/marketing-ops/references/acquire/ads/references/conversion-tracking.md +19 -0
  305. package/.merlin-core/skills/domain/marketing-ops/references/acquire/ads/references/platform-setup-checklists.md +19 -0
  306. package/.merlin-core/skills/domain/marketing-ops/references/acquire/ads.md +322 -0
  307. package/.merlin-core/skills/domain/marketing-ops/references/acquire/ai-seo/references/content-patterns.md +19 -0
  308. package/.merlin-core/skills/domain/marketing-ops/references/acquire/ai-seo/references/content-types.md +19 -0
  309. package/.merlin-core/skills/domain/marketing-ops/references/acquire/ai-seo/references/platform-ranking-factors.md +19 -0
  310. package/.merlin-core/skills/domain/marketing-ops/references/acquire/ai-seo.md +388 -0
  311. package/.merlin-core/skills/domain/marketing-ops/references/acquire/aso/references/apple-specs.md +19 -0
  312. package/.merlin-core/skills/domain/marketing-ops/references/acquire/aso/references/benchmarks.md +19 -0
  313. package/.merlin-core/skills/domain/marketing-ops/references/acquire/aso/references/google-play-specs.md +19 -0
  314. package/.merlin-core/skills/domain/marketing-ops/references/acquire/aso/references/report-template.md +19 -0
  315. package/.merlin-core/skills/domain/marketing-ops/references/acquire/aso/references/scoring-criteria.md +19 -0
  316. package/.merlin-core/skills/domain/marketing-ops/references/acquire/aso.md +316 -0
  317. package/.merlin-core/skills/domain/marketing-ops/references/acquire/co-marketing.md +305 -0
  318. package/.merlin-core/skills/domain/marketing-ops/references/acquire/community-marketing.md +169 -0
  319. package/.merlin-core/skills/domain/marketing-ops/references/acquire/competitor-profiling/references/templates.md +19 -0
  320. package/.merlin-core/skills/domain/marketing-ops/references/acquire/competitor-profiling/references/tool-reference.md +19 -0
  321. package/.merlin-core/skills/domain/marketing-ops/references/acquire/competitor-profiling.md +442 -0
  322. package/.merlin-core/skills/domain/marketing-ops/references/acquire/competitors/references/content-architecture.md +19 -0
  323. package/.merlin-core/skills/domain/marketing-ops/references/acquire/competitors/references/templates.md +19 -0
  324. package/.merlin-core/skills/domain/marketing-ops/references/acquire/competitors.md +281 -0
  325. package/.merlin-core/skills/domain/marketing-ops/references/acquire/content-strategy.md +16 -0
  326. package/.merlin-core/skills/domain/marketing-ops/references/acquire/directory-submissions/references/directory-list.md +19 -0
  327. package/.merlin-core/skills/domain/marketing-ops/references/acquire/directory-submissions/references/positioning-variations.md +19 -0
  328. package/.merlin-core/skills/domain/marketing-ops/references/acquire/directory-submissions/references/submission-tracker-template.md +19 -0
  329. package/.merlin-core/skills/domain/marketing-ops/references/acquire/directory-submissions.md +396 -0
  330. package/.merlin-core/skills/domain/marketing-ops/references/acquire/free-tools/references/tool-types.md +19 -0
  331. package/.merlin-core/skills/domain/marketing-ops/references/acquire/free-tools.md +196 -0
  332. package/.merlin-core/skills/domain/marketing-ops/references/acquire/image/references/ai-image-prompting.md +19 -0
  333. package/.merlin-core/skills/domain/marketing-ops/references/acquire/image.md +352 -0
  334. package/.merlin-core/skills/domain/marketing-ops/references/acquire/launch.md +18 -0
  335. package/.merlin-core/skills/domain/marketing-ops/references/acquire/lead-magnets/references/benchmarks.md +19 -0
  336. package/.merlin-core/skills/domain/marketing-ops/references/acquire/lead-magnets/references/format-guide.md +19 -0
  337. package/.merlin-core/skills/domain/marketing-ops/references/acquire/lead-magnets.md +333 -0
  338. package/.merlin-core/skills/domain/marketing-ops/references/acquire/programmatic-seo.md +16 -0
  339. package/.merlin-core/skills/domain/marketing-ops/references/acquire/schema.md +16 -0
  340. package/.merlin-core/skills/domain/marketing-ops/references/acquire/seo-audit/references/ai-writing-detection.md +19 -0
  341. package/.merlin-core/skills/domain/marketing-ops/references/acquire/seo-audit/references/international-seo.md +19 -0
  342. package/.merlin-core/skills/domain/marketing-ops/references/acquire/seo-audit.md +546 -0
  343. package/.merlin-core/skills/domain/marketing-ops/references/acquire/site-architecture/references/mermaid-templates.md +19 -0
  344. package/.merlin-core/skills/domain/marketing-ops/references/acquire/site-architecture/references/navigation-patterns.md +19 -0
  345. package/.merlin-core/skills/domain/marketing-ops/references/acquire/site-architecture/references/site-type-templates.md +19 -0
  346. package/.merlin-core/skills/domain/marketing-ops/references/acquire/site-architecture.md +371 -0
  347. package/.merlin-core/skills/domain/marketing-ops/references/acquire/social/references/platform-limits.md +19 -0
  348. package/.merlin-core/skills/domain/marketing-ops/references/acquire/social/references/platforms.md +19 -0
  349. package/.merlin-core/skills/domain/marketing-ops/references/acquire/social/references/post-templates.md +19 -0
  350. package/.merlin-core/skills/domain/marketing-ops/references/acquire/social/references/reverse-engineering.md +19 -0
  351. package/.merlin-core/skills/domain/marketing-ops/references/acquire/social/references/short-form-video.md +19 -0
  352. package/.merlin-core/skills/domain/marketing-ops/references/acquire/social.md +431 -0
  353. package/.merlin-core/skills/domain/marketing-ops/references/acquire/video/references/ai-video-prompting.md +19 -0
  354. package/.merlin-core/skills/domain/marketing-ops/references/acquire/video.md +353 -0
  355. package/.merlin-core/skills/domain/marketing-ops/references/activate/ab-testing/references/sample-size-guide.md +19 -0
  356. package/.merlin-core/skills/domain/marketing-ops/references/activate/ab-testing/references/test-templates.md +19 -0
  357. package/.merlin-core/skills/domain/marketing-ops/references/activate/ab-testing.md +379 -0
  358. package/.merlin-core/skills/domain/marketing-ops/references/activate/analytics/references/event-library.md +19 -0
  359. package/.merlin-core/skills/domain/marketing-ops/references/activate/analytics/references/ga4-implementation.md +19 -0
  360. package/.merlin-core/skills/domain/marketing-ops/references/activate/analytics/references/gtm-implementation.md +19 -0
  361. package/.merlin-core/skills/domain/marketing-ops/references/activate/analytics.md +323 -0
  362. package/.merlin-core/skills/domain/marketing-ops/references/activate/copy-editing.md +18 -0
  363. package/.merlin-core/skills/domain/marketing-ops/references/activate/copywriting.md +18 -0
  364. package/.merlin-core/skills/domain/marketing-ops/references/activate/cro/references/experiments.md +19 -0
  365. package/.merlin-core/skills/domain/marketing-ops/references/activate/cro/references/form.md +19 -0
  366. package/.merlin-core/skills/domain/marketing-ops/references/activate/cro.md +211 -0
  367. package/.merlin-core/skills/domain/marketing-ops/references/activate/emails.md +18 -0
  368. package/.merlin-core/skills/domain/marketing-ops/references/activate/paywalls/references/experiments.md +19 -0
  369. package/.merlin-core/skills/domain/marketing-ops/references/activate/paywalls.md +255 -0
  370. package/.merlin-core/skills/domain/marketing-ops/references/activate/popups.md +518 -0
  371. package/.merlin-core/skills/domain/marketing-ops/references/activate/pricing.md +18 -0
  372. package/.merlin-core/skills/domain/marketing-ops/references/activate/sales-enablement/references/deck-frameworks.md +19 -0
  373. package/.merlin-core/skills/domain/marketing-ops/references/activate/sales-enablement/references/demo-scripts.md +19 -0
  374. package/.merlin-core/skills/domain/marketing-ops/references/activate/sales-enablement/references/objection-library.md +19 -0
  375. package/.merlin-core/skills/domain/marketing-ops/references/activate/sales-enablement/references/one-pager-templates.md +19 -0
  376. package/.merlin-core/skills/domain/marketing-ops/references/activate/sales-enablement.md +371 -0
  377. package/.merlin-core/skills/domain/marketing-ops/references/activate/signup.md +406 -0
  378. package/.merlin-core/skills/domain/marketing-ops/references/expand/co-marketing.md +18 -0
  379. package/.merlin-core/skills/domain/marketing-ops/references/expand/community-marketing.md +18 -0
  380. package/.merlin-core/skills/domain/marketing-ops/references/expand/referrals/references/affiliate-programs.md +19 -0
  381. package/.merlin-core/skills/domain/marketing-ops/references/expand/referrals/references/program-examples.md +19 -0
  382. package/.merlin-core/skills/domain/marketing-ops/references/expand/referrals.md +278 -0
  383. package/.merlin-core/skills/domain/marketing-ops/references/foundation/customer-research/references/source-guides.md +425 -0
  384. package/.merlin-core/skills/domain/marketing-ops/references/foundation/customer-research.md +284 -0
  385. package/.merlin-core/skills/domain/marketing-ops/references/foundation/marketing-ideas/references/ideas-by-category.md +216 -0
  386. package/.merlin-core/skills/domain/marketing-ops/references/foundation/marketing-ideas.md +188 -0
  387. package/.merlin-core/skills/domain/marketing-ops/references/foundation/marketing-psychology.md +532 -0
  388. package/.merlin-core/skills/domain/marketing-ops/references/foundation/product-marketing.md +276 -0
  389. package/.merlin-core/skills/domain/marketing-ops/references/retain/churn-prevention/references/cancel-flow-patterns.md +19 -0
  390. package/.merlin-core/skills/domain/marketing-ops/references/retain/churn-prevention/references/dunning-playbook.md +19 -0
  391. package/.merlin-core/skills/domain/marketing-ops/references/retain/churn-prevention.md +442 -0
  392. package/.merlin-core/skills/domain/marketing-ops/references/retain/onboarding/references/experiments.md +19 -0
  393. package/.merlin-core/skills/domain/marketing-ops/references/retain/onboarding.md +243 -0
  394. package/.merlin-core/skills/domain/marketing-ops/references/retain/revops-lifecycle.md +18 -0
  395. package/.merlin-core/skills/domain/marketing-ops/references/retain/revops-operations.md +18 -0
  396. package/.merlin-core/skills/domain/n8n-automation/SKILL.md +149 -0
  397. package/.merlin-core/skills/domain/n8n-automation/references/code-javascript.md +3744 -0
  398. package/.merlin-core/skills/domain/n8n-automation/references/code-python.md +3293 -0
  399. package/.merlin-core/skills/domain/n8n-automation/references/expression-syntax.md +1662 -0
  400. package/.merlin-core/skills/domain/n8n-automation/references/mcp-tools-expert.md +2111 -0
  401. package/.merlin-core/skills/domain/n8n-automation/references/node-configuration.md +2523 -0
  402. package/.merlin-core/skills/domain/n8n-automation/references/validation-expert.md +2491 -0
  403. package/.merlin-core/skills/domain/n8n-automation/references/workflow-patterns.md +4624 -0
  404. package/.merlin-core/skills/domain/ops-manual/SKILL.md +225 -0
  405. package/.merlin-core/skills/domain/ops-manual/references/elicitation-questions.md +141 -0
  406. package/.merlin-core/skills/domain/ops-manual/references/external-skills-registry.md +63 -0
  407. package/.merlin-core/skills/domain/ops-manual/references/operations-template.yaml +132 -0
  408. package/.merlin-core/skills/domain/remotion-best-practices/SKILL.md +99 -0
  409. package/.merlin-core/skills/domain/remotion-best-practices/rules/3d.md +86 -0
  410. package/.merlin-core/skills/domain/remotion-best-practices/rules/animations.md +27 -0
  411. package/.merlin-core/skills/domain/remotion-best-practices/rules/assets/charts-bar-chart.tsx +173 -0
  412. package/.merlin-core/skills/domain/remotion-best-practices/rules/assets/text-animations-typewriter.tsx +100 -0
  413. package/.merlin-core/skills/domain/remotion-best-practices/rules/assets/text-animations-word-highlight.tsx +108 -0
  414. package/.merlin-core/skills/domain/remotion-best-practices/rules/assets.md +78 -0
  415. package/.merlin-core/skills/domain/remotion-best-practices/rules/audio.md +172 -0
  416. package/.merlin-core/skills/domain/remotion-best-practices/rules/calculate-metadata.md +131 -0
  417. package/.merlin-core/skills/domain/remotion-best-practices/rules/can-decode.md +75 -0
  418. package/.merlin-core/skills/domain/remotion-best-practices/rules/charts.md +68 -0
  419. package/.merlin-core/skills/domain/remotion-best-practices/rules/compositions.md +154 -0
  420. package/.merlin-core/skills/domain/remotion-best-practices/rules/display-captions.md +126 -0
  421. package/.merlin-core/skills/domain/remotion-best-practices/rules/extract-frames.md +229 -0
  422. package/.merlin-core/skills/domain/remotion-best-practices/rules/fonts.md +152 -0
  423. package/.merlin-core/skills/domain/remotion-best-practices/rules/get-audio-duration.md +58 -0
  424. package/.merlin-core/skills/domain/remotion-best-practices/rules/get-video-dimensions.md +68 -0
  425. package/.merlin-core/skills/domain/remotion-best-practices/rules/get-video-duration.md +58 -0
  426. package/.merlin-core/skills/domain/remotion-best-practices/rules/gifs.md +144 -0
  427. package/.merlin-core/skills/domain/remotion-best-practices/rules/images.md +134 -0
  428. package/.merlin-core/skills/domain/remotion-best-practices/rules/import-srt-captions.md +67 -0
  429. package/.merlin-core/skills/domain/remotion-best-practices/rules/lottie.md +70 -0
  430. package/.merlin-core/skills/domain/remotion-best-practices/rules/maps.md +414 -0
  431. package/.merlin-core/skills/domain/remotion-best-practices/rules/measuring-dom-nodes.md +34 -0
  432. package/.merlin-core/skills/domain/remotion-best-practices/rules/measuring-text.md +143 -0
  433. package/.merlin-core/skills/domain/remotion-best-practices/rules/parameters.md +109 -0
  434. package/.merlin-core/skills/domain/remotion-best-practices/rules/sequencing.md +118 -0
  435. package/.merlin-core/skills/domain/remotion-best-practices/rules/tailwind.md +11 -0
  436. package/.merlin-core/skills/domain/remotion-best-practices/rules/text-animations.md +20 -0
  437. package/.merlin-core/skills/domain/remotion-best-practices/rules/timing.md +179 -0
  438. package/.merlin-core/skills/domain/remotion-best-practices/rules/transcribe-captions.md +19 -0
  439. package/.merlin-core/skills/domain/remotion-best-practices/rules/transitions.md +137 -0
  440. package/.merlin-core/skills/domain/remotion-best-practices/rules/transparent-videos.md +106 -0
  441. package/.merlin-core/skills/domain/remotion-best-practices/rules/trimming.md +51 -0
  442. package/.merlin-core/skills/domain/remotion-best-practices/rules/videos.md +171 -0
  443. package/.merlin-core/skills/domain/resend-email/SKILL.md +377 -0
  444. package/.merlin-core/skills/general/adversarial-review/SKILL.md +144 -0
  445. package/.merlin-core/skills/general/api-design/SKILL.md +513 -0
  446. package/.merlin-core/skills/general/apify-scrape/SKILL.md +137 -0
  447. package/.merlin-core/skills/general/apify-scrape/scripts/apify-scrape.sh +68 -0
  448. package/.merlin-core/skills/general/backup/SKILL.md +87 -0
  449. package/.merlin-core/skills/general/blkskrn/SKILL.md +392 -0
  450. package/.merlin-core/skills/general/blkskrn/references/animation-patterns.md +521 -0
  451. package/.merlin-core/skills/general/blkskrn/references/design-system.md +637 -0
  452. package/.merlin-core/skills/general/blkskrn/references/html-templates.md +440 -0
  453. package/.merlin-core/skills/general/blkskrn/references/presenter-template.md +45 -0
  454. package/.merlin-core/skills/general/blkskrn/references/slide-types.md +424 -0
  455. package/.merlin-core/skills/general/blkskrn/scripts/canvas-manager.js +502 -0
  456. package/.merlin-core/skills/general/blkskrn/scripts/presenter.js +90 -0
  457. package/.merlin-core/skills/general/blkskrn/templates/presenter.html +273 -0
  458. package/.merlin-core/skills/general/blkskrn/templates/slide-base.html +277 -0
  459. package/.merlin-core/skills/general/blkskrn/templates/viewer.html +165 -0
  460. package/.merlin-core/skills/general/browser-takeover/SKILL.md +53 -0
  461. package/.merlin-core/skills/general/claude-api/SKILL.md +90 -0
  462. package/.merlin-core/skills/general/code-javascript/SKILL.md +268 -0
  463. package/.merlin-core/skills/general/code-python/SKILL.md +424 -0
  464. package/.merlin-core/skills/general/code-style/SKILL.md +97 -0
  465. package/.merlin-core/skills/general/code-typescript/SKILL.md +361 -0
  466. package/.merlin-core/skills/general/cold-email/SKILL.md +164 -0
  467. package/.merlin-core/skills/general/cold-email/references/benchmarks.md +18 -0
  468. package/.merlin-core/skills/general/cold-email/references/follow-up-sequences.md +18 -0
  469. package/.merlin-core/skills/general/cold-email/references/frameworks.md +18 -0
  470. package/.merlin-core/skills/general/cold-email/references/personalization.md +18 -0
  471. package/.merlin-core/skills/general/cold-email/references/subject-lines.md +18 -0
  472. package/.merlin-core/skills/general/container-security/SKILL.md +462 -0
  473. package/.merlin-core/skills/general/context-management/SKILL.md +79 -0
  474. package/.merlin-core/skills/general/copy-editing/SKILL.md +501 -0
  475. package/.merlin-core/skills/general/copy-editing/references/checklist.md +18 -0
  476. package/.merlin-core/skills/general/copy-editing/references/content-refresh.md +18 -0
  477. package/.merlin-core/skills/general/copy-editing/references/plain-english-alternatives.md +18 -0
  478. package/.merlin-core/skills/general/copywriting/SKILL.md +294 -0
  479. package/.merlin-core/skills/general/copywriting/references/copy-frameworks.md +392 -0
  480. package/.merlin-core/skills/general/copywriting/references/natural-transitions.md +276 -0
  481. package/.merlin-core/skills/general/database/SKILL.md +561 -0
  482. package/.merlin-core/skills/general/database/references/postgres-concurrency.md +182 -0
  483. package/.merlin-core/skills/general/database/references/postgres-connections.md +97 -0
  484. package/.merlin-core/skills/general/database/references/postgres-data-patterns.md +159 -0
  485. package/.merlin-core/skills/general/database/references/postgres-monitoring.md +136 -0
  486. package/.merlin-core/skills/general/database/references/postgres-rls.md +140 -0
  487. package/.merlin-core/skills/general/database-provision/SKILL.md +56 -0
  488. package/.merlin-core/skills/general/deploy/SKILL.md +65 -0
  489. package/.merlin-core/skills/general/design-inspiration/SKILL.md +146 -0
  490. package/.merlin-core/skills/general/design-palette/SKILL.md +99 -0
  491. package/.merlin-core/skills/general/design-palette/references/full-palettes.md +144 -0
  492. package/.merlin-core/skills/general/design-system/SKILL.md +94 -0
  493. package/.merlin-core/skills/general/design-typography/SKILL.md +115 -0
  494. package/.merlin-core/skills/general/design-typography/references/full-pairings.md +144 -0
  495. package/.merlin-core/skills/general/design-ux-patterns/SKILL.md +155 -0
  496. package/.merlin-core/skills/general/design-ux-patterns/references/charts-data-guidelines.md +197 -0
  497. package/.merlin-core/skills/general/design-ux-patterns/references/landing-patterns.md +199 -0
  498. package/.merlin-core/skills/general/design-ux-patterns/references/professional-ui-checklist.md +56 -0
  499. package/.merlin-core/skills/general/design-ux-patterns/references/style-catalog.md +89 -0
  500. package/.merlin-core/skills/general/design-ux-patterns/references/ux-guidelines.md +837 -0
  501. package/.merlin-core/skills/general/discover-cloud/SKILL.md +108 -0
  502. package/.merlin-core/skills/general/doc-sync/SKILL.md +52 -0
  503. package/.merlin-core/skills/general/document-sharding/SKILL.md +53 -0
  504. package/.merlin-core/skills/general/docx/SKILL.md +418 -0
  505. package/.merlin-core/skills/general/docx/references/windows-setup.md +27 -0
  506. package/.merlin-core/skills/general/docx/scripts/__init__.py +1 -0
  507. package/.merlin-core/skills/general/docx/scripts/accept_changes.py +135 -0
  508. package/.merlin-core/skills/general/docx/scripts/comment.py +318 -0
  509. package/.merlin-core/skills/general/docx/scripts/office/__init__.py +0 -0
  510. package/.merlin-core/skills/general/docx/scripts/office/helpers/__init__.py +0 -0
  511. package/.merlin-core/skills/general/docx/scripts/office/helpers/merge_runs.py +199 -0
  512. package/.merlin-core/skills/general/docx/scripts/office/helpers/simplify_redlines.py +197 -0
  513. package/.merlin-core/skills/general/docx/scripts/office/pack.py +159 -0
  514. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chart.xsd +1499 -0
  515. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-chartDrawing.xsd +146 -0
  516. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-diagram.xsd +1085 -0
  517. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-lockedCanvas.xsd +11 -0
  518. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-main.xsd +3081 -0
  519. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-picture.xsd +23 -0
  520. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-spreadsheetDrawing.xsd +185 -0
  521. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/dml-wordprocessingDrawing.xsd +287 -0
  522. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/pml.xsd +1676 -0
  523. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-additionalCharacteristics.xsd +28 -0
  524. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-bibliography.xsd +144 -0
  525. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-commonSimpleTypes.xsd +174 -0
  526. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlDataProperties.xsd +25 -0
  527. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-customXmlSchemaProperties.xsd +18 -0
  528. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesCustom.xsd +59 -0
  529. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesExtended.xsd +56 -0
  530. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-documentPropertiesVariantTypes.xsd +195 -0
  531. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-math.xsd +582 -0
  532. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/shared-relationshipReference.xsd +25 -0
  533. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/sml.xsd +4439 -0
  534. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-main.xsd +570 -0
  535. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-officeDrawing.xsd +509 -0
  536. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-presentationDrawing.xsd +12 -0
  537. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-spreadsheetDrawing.xsd +108 -0
  538. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/vml-wordprocessingDrawing.xsd +96 -0
  539. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/wml.xsd +3646 -0
  540. package/.merlin-core/skills/general/docx/scripts/office/schemas/ISO-IEC29500-4_2016/xml.xsd +116 -0
  541. package/.merlin-core/skills/general/docx/scripts/office/schemas/ecma/fouth-edition/opc-contentTypes.xsd +42 -0
  542. package/.merlin-core/skills/general/docx/scripts/office/schemas/ecma/fouth-edition/opc-coreProperties.xsd +50 -0
  543. package/.merlin-core/skills/general/docx/scripts/office/schemas/ecma/fouth-edition/opc-digSig.xsd +49 -0
  544. package/.merlin-core/skills/general/docx/scripts/office/schemas/ecma/fouth-edition/opc-relationships.xsd +33 -0
  545. package/.merlin-core/skills/general/docx/scripts/office/schemas/mce/mc.xsd +75 -0
  546. package/.merlin-core/skills/general/docx/scripts/office/schemas/microsoft/wml-2010.xsd +560 -0
  547. package/.merlin-core/skills/general/docx/scripts/office/schemas/microsoft/wml-2012.xsd +67 -0
  548. package/.merlin-core/skills/general/docx/scripts/office/schemas/microsoft/wml-2018.xsd +14 -0
  549. package/.merlin-core/skills/general/docx/scripts/office/schemas/microsoft/wml-cex-2018.xsd +20 -0
  550. package/.merlin-core/skills/general/docx/scripts/office/schemas/microsoft/wml-cid-2016.xsd +13 -0
  551. package/.merlin-core/skills/general/docx/scripts/office/schemas/microsoft/wml-sdtdatahash-2020.xsd +4 -0
  552. package/.merlin-core/skills/general/docx/scripts/office/schemas/microsoft/wml-symex-2015.xsd +8 -0
  553. package/.merlin-core/skills/general/docx/scripts/office/soffice.py +183 -0
  554. package/.merlin-core/skills/general/docx/scripts/office/unpack.py +132 -0
  555. package/.merlin-core/skills/general/docx/scripts/office/validate.py +111 -0
  556. package/.merlin-core/skills/general/docx/scripts/office/validators/__init__.py +15 -0
  557. package/.merlin-core/skills/general/docx/scripts/office/validators/base.py +847 -0
  558. package/.merlin-core/skills/general/docx/scripts/office/validators/docx.py +446 -0
  559. package/.merlin-core/skills/general/docx/scripts/office/validators/pptx.py +275 -0
  560. package/.merlin-core/skills/general/docx/scripts/office/validators/redlining.py +247 -0
  561. package/.merlin-core/skills/general/docx/scripts/templates/comments.xml +3 -0
  562. package/.merlin-core/skills/general/docx/scripts/templates/commentsExtended.xml +3 -0
  563. package/.merlin-core/skills/general/docx/scripts/templates/commentsExtensible.xml +3 -0
  564. package/.merlin-core/skills/general/docx/scripts/templates/commentsIds.xml +3 -0
  565. package/.merlin-core/skills/general/docx/scripts/templates/people.xml +3 -0
  566. package/.merlin-core/skills/general/elicitation/SKILL.md +188 -0
  567. package/.merlin-core/skills/general/engineering-audit/SKILL.md +122 -0
  568. package/.merlin-core/skills/general/find-and-edit/SKILL.md +102 -0
  569. package/.merlin-core/skills/general/first-party-docs/SKILL.md +51 -0
  570. package/.merlin-core/skills/general/frontend-design/SKILL.md +204 -0
  571. package/.merlin-core/skills/general/guardrails/SKILL.md +144 -0
  572. package/.merlin-core/skills/general/image-gen/SKILL.md +49 -0
  573. package/.merlin-core/skills/general/learning-capture/SKILL.md +192 -0
  574. package/.merlin-core/skills/general/lgpd-compliance-audit/SKILL.md +448 -0
  575. package/.merlin-core/skills/general/load-testing/SKILL.md +114 -0
  576. package/.merlin-core/skills/general/load-testing/docker/Dockerfile.dashboard +21 -0
  577. package/.merlin-core/skills/general/load-testing/docker/docker-compose.locust.yml +39 -0
  578. package/.merlin-core/skills/general/load-testing/requirements.txt +1 -0
  579. package/.merlin-core/skills/general/load-testing/scripts/compare_baseline.py +172 -0
  580. package/.merlin-core/skills/general/load-testing/scripts/run_local.py +245 -0
  581. package/.merlin-core/skills/general/load-testing/templates/load_shape_stepped.py +35 -0
  582. package/.merlin-core/skills/general/load-testing/templates/locustfile_dashboard.py +47 -0
  583. package/.merlin-core/skills/general/load-testing/templates/threshold_hook.py +36 -0
  584. package/.merlin-core/skills/general/mage-beauty/SKILL.md +89 -0
  585. package/.merlin-core/skills/general/mage-beauty/references/anti-patterns.md +148 -0
  586. package/.merlin-core/skills/general/mage-beauty/references/color-and-contrast.md +87 -0
  587. package/.merlin-core/skills/general/mage-beauty/references/interaction-design.md +99 -0
  588. package/.merlin-core/skills/general/mage-beauty/references/motion-design.md +90 -0
  589. package/.merlin-core/skills/general/mage-beauty/references/remotion-bridge.md +187 -0
  590. package/.merlin-core/skills/general/mage-beauty/references/responsive-and-multi-format.md +98 -0
  591. package/.merlin-core/skills/general/mage-beauty/references/spatial-design.md +88 -0
  592. package/.merlin-core/skills/general/mage-beauty/references/typography.md +60 -0
  593. package/.merlin-core/skills/general/mage-beauty/references/verb-adapt.md +102 -0
  594. package/.merlin-core/skills/general/mage-beauty/references/verb-animate.md +97 -0
  595. package/.merlin-core/skills/general/mage-beauty/references/verb-audit.md +99 -0
  596. package/.merlin-core/skills/general/mage-beauty/references/verb-bolder.md +94 -0
  597. package/.merlin-core/skills/general/mage-beauty/references/verb-cinematic.md +128 -0
  598. package/.merlin-core/skills/general/mage-beauty/references/verb-clarify.md +107 -0
  599. package/.merlin-core/skills/general/mage-beauty/references/verb-colorize.md +106 -0
  600. package/.merlin-core/skills/general/mage-beauty/references/verb-critique.md +88 -0
  601. package/.merlin-core/skills/general/mage-beauty/references/verb-delight.md +98 -0
  602. package/.merlin-core/skills/general/mage-beauty/references/verb-distill.md +97 -0
  603. package/.merlin-core/skills/general/mage-beauty/references/verb-harden.md +79 -0
  604. package/.merlin-core/skills/general/mage-beauty/references/verb-layout.md +104 -0
  605. package/.merlin-core/skills/general/mage-beauty/references/verb-onboard.md +98 -0
  606. package/.merlin-core/skills/general/mage-beauty/references/verb-optimize.md +124 -0
  607. package/.merlin-core/skills/general/mage-beauty/references/verb-overdrive.md +105 -0
  608. package/.merlin-core/skills/general/mage-beauty/references/verb-polish.md +91 -0
  609. package/.merlin-core/skills/general/mage-beauty/references/verb-quieter.md +95 -0
  610. package/.merlin-core/skills/general/mage-beauty/references/verb-rebrand.md +127 -0
  611. package/.merlin-core/skills/general/mage-beauty/references/verb-shape.md +160 -0
  612. package/.merlin-core/skills/general/mage-beauty/references/verb-typeset.md +109 -0
  613. package/.merlin-core/skills/general/mage-beauty/references/voice-and-microcopy.md +137 -0
  614. package/.merlin-core/skills/general/mcp-builder/SKILL.md +92 -0
  615. package/.merlin-core/skills/general/network-debug/SKILL.md +51 -0
  616. package/.merlin-core/skills/general/next-best-practices/SKILL.md +177 -0
  617. package/.merlin-core/skills/general/next-best-practices/references/async-patterns.md +87 -0
  618. package/.merlin-core/skills/general/next-best-practices/references/bundling.md +182 -0
  619. package/.merlin-core/skills/general/next-best-practices/references/data-patterns.md +306 -0
  620. package/.merlin-core/skills/general/next-best-practices/references/debug-tricks.md +125 -0
  621. package/.merlin-core/skills/general/next-best-practices/references/directives.md +74 -0
  622. package/.merlin-core/skills/general/next-best-practices/references/error-handling.md +232 -0
  623. package/.merlin-core/skills/general/next-best-practices/references/file-conventions.md +141 -0
  624. package/.merlin-core/skills/general/next-best-practices/references/font.md +257 -0
  625. package/.merlin-core/skills/general/next-best-practices/references/functions.md +108 -0
  626. package/.merlin-core/skills/general/next-best-practices/references/hydration-error.md +88 -0
  627. package/.merlin-core/skills/general/next-best-practices/references/image.md +179 -0
  628. package/.merlin-core/skills/general/next-best-practices/references/metadata.md +296 -0
  629. package/.merlin-core/skills/general/next-best-practices/references/parallel-routes.md +298 -0
  630. package/.merlin-core/skills/general/next-best-practices/references/route-handlers.md +146 -0
  631. package/.merlin-core/skills/general/next-best-practices/references/rsc-boundaries.md +164 -0
  632. package/.merlin-core/skills/general/next-best-practices/references/runtime-selection.md +40 -0
  633. package/.merlin-core/skills/general/next-best-practices/references/scripts.md +141 -0
  634. package/.merlin-core/skills/general/next-best-practices/references/self-hosting.md +384 -0
  635. package/.merlin-core/skills/general/next-best-practices/references/suspense-boundaries.md +67 -0
  636. package/.merlin-core/skills/general/next-steps/SKILL.md +43 -0
  637. package/.merlin-core/skills/general/party-mode/SKILL.md +57 -0
  638. package/.merlin-core/skills/general/pdf/SKILL.md +298 -0
  639. package/.merlin-core/skills/general/pdf/references/forms.md +312 -0
  640. package/.merlin-core/skills/general/pdf/references/reference.md +640 -0
  641. package/.merlin-core/skills/general/pdf/references/windows-setup.md +40 -0
  642. package/.merlin-core/skills/general/pdf/scripts/check_bounding_boxes.py +65 -0
  643. package/.merlin-core/skills/general/pdf/scripts/check_fillable_fields.py +11 -0
  644. package/.merlin-core/skills/general/pdf/scripts/convert_pdf_to_images.py +33 -0
  645. package/.merlin-core/skills/general/pdf/scripts/create_validation_image.py +37 -0
  646. package/.merlin-core/skills/general/pdf/scripts/extract_form_field_info.py +122 -0
  647. package/.merlin-core/skills/general/pdf/scripts/extract_form_structure.py +115 -0
  648. package/.merlin-core/skills/general/pdf/scripts/fill_fillable_fields.py +98 -0
  649. package/.merlin-core/skills/general/pdf/scripts/fill_pdf_form_with_annotations.py +107 -0
  650. package/.merlin-core/skills/general/pptx/SKILL.md +133 -0
  651. package/.merlin-core/skills/general/pptx/references/editing.md +213 -0
  652. package/.merlin-core/skills/general/pptx/references/pptxgenjs.md +581 -0
  653. package/.merlin-core/skills/general/pptx/references/windows-setup.md +27 -0
  654. package/.merlin-core/skills/general/pptx/scripts/__init__.py +0 -0
  655. package/.merlin-core/skills/general/pptx/scripts/add_slide.py +195 -0
  656. package/.merlin-core/skills/general/pptx/scripts/clean.py +286 -0
  657. package/.merlin-core/skills/general/pptx/scripts/thumbnail.py +289 -0
  658. package/.merlin-core/skills/general/property-testing/SKILL.md +214 -0
  659. package/.merlin-core/skills/general/purge-leaked-secret/SKILL.md +383 -0
  660. package/.merlin-core/skills/general/reflection/SKILL.md +100 -0
  661. package/.merlin-core/skills/general/secret-safe-commit/SKILL.md +246 -0
  662. package/.merlin-core/skills/general/secret-safe-commit/templates/.gitleaks.toml +91 -0
  663. package/.merlin-core/skills/general/secret-safe-commit/templates/.pre-commit-config.yaml +57 -0
  664. package/.merlin-core/skills/general/secret-safe-commit/templates/secret-scan.yml +48 -0
  665. package/.merlin-core/skills/general/semantic-search/SKILL.md +79 -0
  666. package/.merlin-core/skills/general/skill-creator/SKILL.md +342 -0
  667. package/.merlin-core/skills/general/skill-creator/agents/analyzer.md +283 -0
  668. package/.merlin-core/skills/general/skill-creator/agents/comparator.md +211 -0
  669. package/.merlin-core/skills/general/skill-creator/agents/grader.md +227 -0
  670. package/.merlin-core/skills/general/skill-creator/assets/eval_review.html +146 -0
  671. package/.merlin-core/skills/general/skill-creator/eval-viewer/generate_review.py +471 -0
  672. package/.merlin-core/skills/general/skill-creator/eval-viewer/viewer.html +1325 -0
  673. package/.merlin-core/skills/general/skill-creator/references/schemas.md +439 -0
  674. package/.merlin-core/skills/general/skill-creator/scripts/__init__.py +0 -0
  675. package/.merlin-core/skills/general/skill-creator/scripts/aggregate_benchmark.py +401 -0
  676. package/.merlin-core/skills/general/skill-creator/scripts/generate_report.py +326 -0
  677. package/.merlin-core/skills/general/skill-creator/scripts/improve_description.py +247 -0
  678. package/.merlin-core/skills/general/skill-creator/scripts/package_skill.py +136 -0
  679. package/.merlin-core/skills/general/skill-creator/scripts/quick_validate.py +103 -0
  680. package/.merlin-core/skills/general/skill-creator/scripts/run_eval.py +310 -0
  681. package/.merlin-core/skills/general/skill-creator/scripts/run_loop.py +328 -0
  682. package/.merlin-core/skills/general/skill-creator/scripts/utils.py +47 -0
  683. package/.merlin-core/skills/general/start-here/SKILL.md +63 -0
  684. package/.merlin-core/skills/general/start-here/recipes.json +758 -0
  685. package/.merlin-core/skills/general/start-here/recipes.schema.json +57 -0
  686. package/.merlin-core/skills/general/static-analysis/SKILL.md +151 -0
  687. package/.merlin-core/skills/general/tailwind-design-system/SKILL.md +201 -0
  688. package/.merlin-core/skills/general/tailwind-design-system/references/advanced-v4.md +152 -0
  689. package/.merlin-core/skills/general/tailwind-design-system/references/component-patterns.md +353 -0
  690. package/.merlin-core/skills/general/teach-method/SKILL.md +86 -0
  691. package/.merlin-core/skills/general/team-execution/SKILL.md +67 -0
  692. package/.merlin-core/skills/general/testing/SKILL.md +412 -0
  693. package/.merlin-core/skills/general/token-economy/SKILL.md +55 -0
  694. package/.merlin-core/skills/general/vps-security-hardening/SKILL.md +406 -0
  695. package/.merlin-core/skills/general/web-quality/SKILL.md +180 -0
  696. package/.merlin-core/skills/general/webapp-testing/SKILL.md +153 -0
  697. package/.merlin-core/skills/general/webapp-testing/scripts/screenshot_compare.py +72 -0
  698. package/.merlin-core/skills/general/webapp-testing/scripts/with_server.py +103 -0
  699. package/.merlin-core/skills/general/xlsx/SKILL.md +167 -0
  700. package/.merlin-core/skills/general/xlsx/references/nodejs-sheetjs-styled-reports.md +141 -0
  701. package/.merlin-core/skills/general/xlsx/references/windows-setup.md +17 -0
  702. package/.merlin-core/skills/general/xlsx/scripts/recalc.py +184 -0
  703. package/.merlin-core/skills/general/xlsx/scripts/styled-report.js +130 -0
  704. package/.merlin-core/skills/general/yolo-mode/SKILL.md +60 -0
  705. package/.merlin-core/skills/general/youtube-transcript/SKILL.md +177 -0
  706. package/.merlin-core/skills/general/youtube-transcript/scripts/fetch_transcript.py +188 -0
  707. package/.merlin-core/skills/general/youtube-transcript/scripts/gladia_transcribe.mjs +230 -0
  708. package/.merlin-core/tools/commands/activate.js +72 -0
  709. package/.merlin-core/tools/commands/archive-thoughts.js +181 -0
  710. package/.merlin-core/tools/commands/backup.js +156 -0
  711. package/.merlin-core/tools/commands/certify-process.js +196 -0
  712. package/.merlin-core/tools/commands/convert.js +87 -0
  713. package/.merlin-core/tools/commands/cron.js +147 -0
  714. package/.merlin-core/tools/commands/disable.js +73 -0
  715. package/.merlin-core/tools/commands/doc-sync.js +127 -0
  716. package/.merlin-core/tools/commands/eval-skill.js +193 -0
  717. package/.merlin-core/tools/commands/frontmatter.js +49 -0
  718. package/.merlin-core/tools/commands/heartbeat.js +43 -0
  719. package/.merlin-core/tools/commands/index-thoughts.js +35 -0
  720. package/.merlin-core/tools/commands/install-remote-approve.js +184 -0
  721. package/.merlin-core/tools/commands/install.js +81 -0
  722. package/.merlin-core/tools/commands/lib/__verify__/diff-reports.js +170 -0
  723. package/.merlin-core/tools/commands/lib/fs-safe.js +186 -0
  724. package/.merlin-core/tools/commands/lib/preflight.js +607 -0
  725. package/.merlin-core/tools/commands/lib/preserve.js +232 -0
  726. package/.merlin-core/tools/commands/lib/project-config.template.yaml +69 -0
  727. package/.merlin-core/tools/commands/lib/report.js +231 -0
  728. package/.merlin-core/tools/commands/lib/settings-merge.js +134 -0
  729. package/.merlin-core/tools/commands/license.js +52 -0
  730. package/.merlin-core/tools/commands/list.js +125 -0
  731. package/.merlin-core/tools/commands/migrate-alkimia.js +271 -0
  732. package/.merlin-core/tools/commands/modules.js +68 -0
  733. package/.merlin-core/tools/commands/provision.js +83 -0
  734. package/.merlin-core/tools/commands/prune-feedback.js +114 -0
  735. package/.merlin-core/tools/commands/run-process.js +28 -0
  736. package/.merlin-core/tools/commands/state.js +79 -0
  737. package/.merlin-core/tools/commands/sync-bridges.js +197 -0
  738. package/.merlin-core/tools/commands/upgrade.js +1135 -0
  739. package/.merlin-core/tools/commands/validate-recipes.js +218 -0
  740. package/.merlin-core/tools/commands/validate.js +159 -0
  741. package/.merlin-core/tools/commands/yolo.js +82 -0
  742. package/.merlin-core/tools/compose-rules.mjs +179 -0
  743. package/.merlin-core/tools/disable-module.mjs +150 -0
  744. package/.merlin-core/tools/lib/deployer.mjs +131 -0
  745. package/.merlin-core/tools/lib/modules-activation.mjs +225 -0
  746. package/.merlin-core/tools/merlin-tools.js +153 -0
  747. package/.merlin-core/tools/migrate-frontmatter-v3.js +192 -0
  748. package/.merlin-core/tools/modules-catalog.mjs +174 -0
  749. package/.merlin-core/tools/provision-module.mjs +191 -0
  750. package/.merlin-core/tools/verify-module.mjs +99 -0
  751. package/.merlin-core/tools/vps-security-audit.sh +234 -0
  752. package/INSTALL.md +312 -0
  753. package/LICENSE +118 -0
  754. package/PRIVACY-LICENSING.md +65 -0
  755. package/README.md +391 -0
  756. package/bin/README.md +15 -0
  757. package/bin/convert-to-merlin.sh +109 -0
  758. package/bin/fleet-patch-hooks.sh +144 -0
  759. package/bin/fleet-patch-v3-fixes.sh +127 -0
  760. package/bin/merlin-init.js +232 -0
  761. package/bin/merlin.js +321 -0
  762. package/package.json +127 -0
@@ -0,0 +1,3293 @@
1
+ <!-- Adapted from czlonkowski/n8n-skills (MIT). Source files: SKILL.md, DATA_ACCESS.md, ERROR_PATTERNS.md, COMMON_PATTERNS.md, STANDARD_LIBRARY.md -->
2
+
3
+ # Python Code Node (Beta)
4
+
5
+ Expert guidance for writing Python code in n8n Code nodes.
6
+
7
+ > **Cross-references:** [code-javascript.md](code-javascript.md) (preferred alternative) | [expression-syntax.md](expression-syntax.md)
8
+
9
+ ---
10
+
11
+ ## IMPORTANT: JavaScript First
12
+
13
+ **Recommendation**: Use **JavaScript for 95% of use cases**. Only use Python when:
14
+
15
+ - You need specific Python standard library functions
16
+ - You're significantly more comfortable with Python syntax
17
+ - You're doing data transformations better suited to Python
18
+
19
+ **Why JavaScript is preferred:**
20
+
21
+ - Full n8n helper functions ($helpers.httpRequest, etc.)
22
+ - Luxon DateTime library for advanced date/time operations
23
+ - No external library limitations
24
+ - Better n8n documentation and community support
25
+
26
+ ---
27
+
28
+ ## Quick Start
29
+
30
+ ```python
31
+ # Basic template for Python Code nodes
32
+ items = _input.all()
33
+
34
+ # Process data
35
+ processed = []
36
+ for item in items:
37
+ processed.append({
38
+ "json": {
39
+ **item["json"],
40
+ "processed": True,
41
+ "timestamp": datetime.now().isoformat()
42
+ }
43
+ })
44
+
45
+ return processed
46
+ ```
47
+
48
+ ### Essential Rules
49
+
50
+ 1. **Consider JavaScript first** - Use Python only when necessary
51
+ 2. **Access data**: `_input.all()`, `_input.first()`, or `_input.item`
52
+ 3. **CRITICAL**: Must return `[{"json": {...}}]` format
53
+ 4. **CRITICAL**: Webhook data is under `_json["body"]` (not `_json` directly)
54
+ 5. **CRITICAL LIMITATION**: **No external libraries** (no requests, pandas, numpy)
55
+ 6. **Standard library only**: json, datetime, re, base64, hashlib, urllib.parse, math, random, statistics
56
+
57
+ ---
58
+
59
+ ## Mode Selection Guide
60
+
61
+ Same as JavaScript - choose based on your use case:
62
+
63
+ ### Run Once for All Items (Recommended - Default)
64
+
65
+ **Use this mode for:** 95% of use cases
66
+
67
+ - **How it works**: Code executes **once** regardless of input count
68
+ - **Data access**: `_input.all()` or `_items` array (Native mode)
69
+ - **Best for**: Aggregation, filtering, batch processing, transformations
70
+ - **Performance**: Faster for multiple items (single execution)
71
+
72
+ ```python
73
+ # Example: Calculate total from all items
74
+ all_items = _input.all()
75
+ total = sum(item["json"].get("amount", 0) for item in all_items)
76
+
77
+ return [{
78
+ "json": {
79
+ "total": total,
80
+ "count": len(all_items),
81
+ "average": total / len(all_items) if all_items else 0
82
+ }
83
+ }]
84
+ ```
85
+
86
+ ### Run Once for Each Item
87
+
88
+ **Use this mode for:** Specialized cases only
89
+
90
+ - **How it works**: Code executes **separately** for each input item
91
+ - **Data access**: `_input.item` or `_item` (Native mode)
92
+ - **Best for**: Item-specific logic, independent operations, per-item validation
93
+ - **Performance**: Slower for large datasets (multiple executions)
94
+
95
+ ```python
96
+ # Example: Add processing timestamp to each item
97
+ item = _input.item
98
+
99
+ return [{
100
+ "json": {
101
+ **item["json"],
102
+ "processed": True,
103
+ "processed_at": datetime.now().isoformat()
104
+ }
105
+ }]
106
+ ```
107
+
108
+ ---
109
+
110
+ ## Python Modes: Beta vs Native
111
+
112
+ n8n offers two Python execution modes:
113
+
114
+ ### Python (Beta) - Recommended
115
+
116
+ - **Use**: `_input`, `_json`, `_node` helper syntax
117
+ - **Best for**: Most Python use cases
118
+ - **Helpers available**: `_now`, `_today`, `_jmespath()`
119
+ - **Import**: `from datetime import datetime`
120
+
121
+ ```python
122
+ # Python (Beta) example
123
+ items = _input.all()
124
+ now = _now # Built-in datetime object
125
+
126
+ return [{
127
+ "json": {
128
+ "count": len(items),
129
+ "timestamp": now.isoformat()
130
+ }
131
+ }]
132
+ ```
133
+
134
+ ### Python (Native) (Beta)
135
+
136
+ - **Use**: `_items`, `_item` variables only
137
+ - **No helpers**: No `_input`, `_now`, etc.
138
+ - **More limited**: Standard Python only
139
+ - **Use when**: Need pure Python without n8n helpers
140
+
141
+ ```python
142
+ # Python (Native) example
143
+ processed = []
144
+
145
+ for item in _items:
146
+ processed.append({
147
+ "json": {
148
+ "id": item["json"].get("id"),
149
+ "processed": True
150
+ }
151
+ })
152
+
153
+ return processed
154
+ ```
155
+
156
+ **Recommendation**: Use **Python (Beta)** for better n8n integration.
157
+
158
+ ---
159
+
160
+ ## Critical: Webhook Data Structure
161
+
162
+ **MOST COMMON MISTAKE**: Webhook data is nested under `["body"]`
163
+
164
+ ```python
165
+ # WRONG - Will raise KeyError
166
+ name = _json["name"]
167
+ email = _json["email"]
168
+
169
+ # CORRECT - Webhook data is under ["body"]
170
+ name = _json["body"]["name"]
171
+ email = _json["body"]["email"]
172
+
173
+ # SAFER - Use .get() for safe access
174
+ webhook_data = _json.get("body", {})
175
+ name = webhook_data.get("name")
176
+ ```
177
+
178
+ **Why**: Webhook node wraps all request data under `body` property. This includes POST data, query parameters, and JSON payloads.
179
+
180
+ ---
181
+
182
+ ## Return Format Requirements
183
+
184
+ **CRITICAL RULE**: Always return list of dictionaries with `"json"` key
185
+
186
+ ### Correct Return Formats
187
+
188
+ ```python
189
+ # Single result
190
+ return [{
191
+ "json": {
192
+ "field1": value1,
193
+ "field2": value2
194
+ }
195
+ }]
196
+
197
+ # Multiple results
198
+ return [
199
+ {"json": {"id": 1, "data": "first"}},
200
+ {"json": {"id": 2, "data": "second"}}
201
+ ]
202
+
203
+ # List comprehension
204
+ transformed = [
205
+ {"json": {"id": item["json"]["id"], "processed": True}}
206
+ for item in _input.all()
207
+ if item["json"].get("valid")
208
+ ]
209
+ return transformed
210
+
211
+ # Empty result (when no data to return)
212
+ return []
213
+
214
+ # Conditional return
215
+ if should_process:
216
+ return [{"json": processed_data}]
217
+ else:
218
+ return []
219
+ ```
220
+
221
+ ### Incorrect Return Formats
222
+
223
+ ```python
224
+ # WRONG: Dictionary without list wrapper
225
+ return {
226
+ "json": {"field": value}
227
+ }
228
+
229
+ # WRONG: List without json wrapper
230
+ return [{"field": value}]
231
+
232
+ # WRONG: Plain string
233
+ return "processed"
234
+
235
+ # WRONG: Incomplete structure
236
+ return [{"data": value}] # Should be {"json": value}
237
+ ```
238
+
239
+ **Why it matters**: Next nodes expect list format. Incorrect format causes workflow execution to fail.
240
+
241
+ ---
242
+
243
+ ## When to Use Python vs JavaScript
244
+
245
+ ### Use Python When:
246
+
247
+ - You need `statistics` module for statistical operations
248
+ - You're significantly more comfortable with Python syntax
249
+ - Your logic maps well to list comprehensions
250
+ - You need specific standard library functions
251
+
252
+ ### Use JavaScript When:
253
+
254
+ - You need HTTP requests ($helpers.httpRequest())
255
+ - You need advanced date/time (DateTime/Luxon)
256
+ - You want better n8n integration
257
+ - **For 95% of use cases** (recommended)
258
+
259
+ ### Consider Other Nodes When:
260
+
261
+ - Simple field mapping -> Use **Set** node
262
+ - Basic filtering -> Use **Filter** node
263
+ - Simple conditionals -> Use **IF** or **Switch** node
264
+ - HTTP requests only -> Use **HTTP Request** node
265
+
266
+ ---
267
+
268
+ ## Best Practices
269
+
270
+ ### 1. Always Use .get() for Dictionary Access
271
+
272
+ ```python
273
+ # SAFE: Won't crash if field missing
274
+ value = item["json"].get("field", "default")
275
+
276
+ # RISKY: Crashes if field doesn't exist
277
+ value = item["json"]["field"]
278
+ ```
279
+
280
+ ### 2. Handle None/Null Values Explicitly
281
+
282
+ ```python
283
+ # GOOD: Default to 0 if None
284
+ amount = item["json"].get("amount") or 0
285
+
286
+ # GOOD: Check for None explicitly
287
+ text = item["json"].get("text")
288
+ if text is None:
289
+ text = ""
290
+ ```
291
+
292
+ ### 3. Use List Comprehensions for Filtering
293
+
294
+ ```python
295
+ # PYTHONIC: List comprehension
296
+ valid = [item for item in items if item["json"].get("active")]
297
+
298
+ # VERBOSE: Manual loop
299
+ valid = []
300
+ for item in items:
301
+ if item["json"].get("active"):
302
+ valid.append(item)
303
+ ```
304
+
305
+ ### 4. Return Consistent Structure
306
+
307
+ ```python
308
+ # CONSISTENT: Always list with "json" key
309
+ return [{"json": result}] # Single result
310
+ return results # Multiple results (already formatted)
311
+ return [] # No results
312
+ ```
313
+
314
+ ### 5. Debug with print() Statements
315
+
316
+ ```python
317
+ # Debug statements appear in browser console (F12)
318
+ items = _input.all()
319
+ print(f"Processing {len(items)} items")
320
+ print(f"First item: {items[0] if items else 'None'}")
321
+ ```
322
+
323
+ ---
324
+
325
+ ## Quick Reference Checklist
326
+
327
+ Before deploying Python Code nodes, verify:
328
+
329
+ - [ ] **Considered JavaScript first** - Using Python only when necessary
330
+ - [ ] **Code is not empty** - Must have meaningful logic
331
+ - [ ] **Return statement exists** - Must return list of dictionaries
332
+ - [ ] **Proper return format** - Each item: `{"json": {...}}`
333
+ - [ ] **Data access correct** - Using `_input.all()`, `_input.first()`, or `_input.item`
334
+ - [ ] **No external imports** - Only standard library (json, datetime, re, etc.)
335
+ - [ ] **Safe dictionary access** - Using `.get()` to avoid KeyError
336
+ - [ ] **Webhook data** - Access via `["body"]` if from webhook
337
+ - [ ] **Mode selection** - "All Items" for most cases
338
+ - [ ] **Output consistent** - All code paths return same structure
339
+
340
+ ---
341
+
342
+ ## Integration with Other Skills
343
+
344
+ ### Works With:
345
+
346
+ **n8n Expression Syntax**:
347
+
348
+ - Expressions use `{{ }}` syntax in other nodes
349
+ - Code nodes use Python directly (no `{{ }}`)
350
+ - When to use expressions vs code
351
+
352
+ **n8n MCP Tools Expert**:
353
+
354
+ - How to find Code node: `search_nodes({query: "code"})`
355
+ - Get configuration help: `get_node_essentials("nodes-base.code")`
356
+ - Validate code: `validate_node_operation()`
357
+
358
+ **n8n Node Configuration**:
359
+
360
+ - Mode selection (All Items vs Each Item)
361
+ - Language selection (Python vs JavaScript)
362
+ - Understanding property dependencies
363
+
364
+ **n8n Workflow Patterns**:
365
+
366
+ - Code nodes in transformation step
367
+ - When to use Python vs JavaScript in patterns
368
+
369
+ **n8n Validation Expert**:
370
+
371
+ - Validate Code node configuration
372
+ - Handle validation errors
373
+ - Auto-fix common issues
374
+
375
+ **n8n Code JavaScript**:
376
+
377
+ - When to use JavaScript instead
378
+ - Comparison of JavaScript vs Python features
379
+ - Migration from Python to JavaScript
380
+
381
+ ---
382
+
383
+ # Data Access Patterns - Python Code Node
384
+
385
+ Complete guide to accessing data in n8n Code nodes using Python.
386
+
387
+ ---
388
+
389
+ ## Overview
390
+
391
+ In n8n Python Code nodes, you access data using **underscore-prefixed** variables: `_input`, `_json`, `_node`.
392
+
393
+ **Data Access Priority** (by common usage):
394
+
395
+ 1. **`_input.all()`** - Most common - Batch operations, aggregations
396
+ 2. **`_input.first()`** - Very common - Single item operations
397
+ 3. **`_input.item`** - Common - Each Item mode only
398
+ 4. **`_node["NodeName"]["json"]`** - Specific node references
399
+ 5. **`_json`** - Direct current item (use `_input` instead)
400
+
401
+ **Python vs JavaScript**:
402
+ | JavaScript | Python (Beta) | Python (Native) |
403
+ |------------|---------------|-----------------|
404
+ | `$input.all()` | `_input.all()` | `_items` |
405
+ | `$input.first()` | `_input.first()` | `_items[0]` |
406
+ | `$input.item` | `_input.item` | `_item` |
407
+ | `$json` | `_json` | `_item["json"]` |
408
+ | `$node["Name"]` | `_node["Name"]` | Not available |
409
+
410
+ ---
411
+
412
+ ## Pattern 1: \_input.all() - Process All Items
413
+
414
+ **Usage**: Most common pattern for batch processing
415
+
416
+ **When to use:**
417
+
418
+ - Processing multiple records
419
+ - Aggregating data (sum, count, average)
420
+ - Filtering lists
421
+ - Transforming datasets
422
+
423
+ ### Basic Usage
424
+
425
+ ```python
426
+ # Get all items from previous node
427
+ all_items = _input.all()
428
+
429
+ # all_items is a list of dictionaries like:
430
+ # [
431
+ # {"json": {"id": 1, "name": "Alice"}},
432
+ # {"json": {"id": 2, "name": "Bob"}}
433
+ # ]
434
+
435
+ print(f"Received {len(all_items)} items")
436
+
437
+ return all_items
438
+ ```
439
+
440
+ ### Example 1: Filter Active Items
441
+
442
+ ```python
443
+ all_items = _input.all()
444
+
445
+ # Filter only active items
446
+ active_items = [
447
+ item for item in all_items
448
+ if item["json"].get("status") == "active"
449
+ ]
450
+
451
+ return active_items
452
+ ```
453
+
454
+ ### Example 2: Transform All Items
455
+
456
+ ```python
457
+ all_items = _input.all()
458
+
459
+ # Transform to new structure
460
+ transformed = []
461
+ for item in all_items:
462
+ transformed.append({
463
+ "json": {
464
+ "id": item["json"].get("id"),
465
+ "full_name": f"{item['json'].get('first_name', '')} {item['json'].get('last_name', '')}",
466
+ "email": item["json"].get("email"),
467
+ "processed_at": datetime.now().isoformat()
468
+ }
469
+ })
470
+
471
+ return transformed
472
+ ```
473
+
474
+ ### Example 3: Aggregate Data
475
+
476
+ ```python
477
+ all_items = _input.all()
478
+
479
+ # Calculate total
480
+ total = sum(item["json"].get("amount", 0) for item in all_items)
481
+
482
+ return [{
483
+ "json": {
484
+ "total": total,
485
+ "count": len(all_items),
486
+ "average": total / len(all_items) if all_items else 0
487
+ }
488
+ }]
489
+ ```
490
+
491
+ ### Example 4: Sort and Limit
492
+
493
+ ```python
494
+ all_items = _input.all()
495
+
496
+ # Get top 5 by score
497
+ sorted_items = sorted(
498
+ all_items,
499
+ key=lambda item: item["json"].get("score", 0),
500
+ reverse=True
501
+ )
502
+ top_five = sorted_items[:5]
503
+
504
+ return [{"json": item["json"]} for item in top_five]
505
+ ```
506
+
507
+ ### Example 5: Group By Category
508
+
509
+ ```python
510
+ all_items = _input.all()
511
+
512
+ # Group items by category
513
+ grouped = {}
514
+ for item in all_items:
515
+ category = item["json"].get("category", "Uncategorized")
516
+
517
+ if category not in grouped:
518
+ grouped[category] = []
519
+
520
+ grouped[category].append(item["json"])
521
+
522
+ # Convert to list format
523
+ return [
524
+ {
525
+ "json": {
526
+ "category": category,
527
+ "items": items,
528
+ "count": len(items)
529
+ }
530
+ }
531
+ for category, items in grouped.items()
532
+ ]
533
+ ```
534
+
535
+ ### Example 6: Deduplicate by ID
536
+
537
+ ```python
538
+ all_items = _input.all()
539
+
540
+ # Remove duplicates by ID
541
+ seen = set()
542
+ unique = []
543
+
544
+ for item in all_items:
545
+ item_id = item["json"].get("id")
546
+
547
+ if item_id and item_id not in seen:
548
+ seen.add(item_id)
549
+ unique.append(item)
550
+
551
+ return unique
552
+ ```
553
+
554
+ ---
555
+
556
+ ## Pattern 2: \_input.first() - Get First Item
557
+
558
+ **Usage**: Very common for single-item operations
559
+
560
+ **When to use:**
561
+
562
+ - Previous node returns single object
563
+ - Working with API responses
564
+ - Getting initial/first data point
565
+
566
+ ### Basic Usage
567
+
568
+ ```python
569
+ # Get first item from previous node
570
+ first_item = _input.first()
571
+
572
+ # Access the JSON data
573
+ data = first_item["json"]
574
+
575
+ print(f"First item: {data}")
576
+
577
+ return [{"json": data}]
578
+ ```
579
+
580
+ ### Example 1: Process Single API Response
581
+
582
+ ```python
583
+ # Get API response (typically single object)
584
+ response = _input.first()["json"]
585
+
586
+ # Extract what you need
587
+ return [{
588
+ "json": {
589
+ "user_id": response.get("data", {}).get("user", {}).get("id"),
590
+ "user_name": response.get("data", {}).get("user", {}).get("name"),
591
+ "status": response.get("status"),
592
+ "fetched_at": datetime.now().isoformat()
593
+ }
594
+ }]
595
+ ```
596
+
597
+ ### Example 2: Transform Single Object
598
+
599
+ ```python
600
+ data = _input.first()["json"]
601
+
602
+ # Transform structure
603
+ return [{
604
+ "json": {
605
+ "id": data.get("id"),
606
+ "contact": {
607
+ "email": data.get("email"),
608
+ "phone": data.get("phone")
609
+ },
610
+ "address": {
611
+ "street": data.get("street"),
612
+ "city": data.get("city"),
613
+ "zip": data.get("zip")
614
+ }
615
+ }
616
+ }]
617
+ ```
618
+
619
+ ### Example 3: Validate Single Item
620
+
621
+ ```python
622
+ item = _input.first()["json"]
623
+
624
+ # Validation logic
625
+ is_valid = bool(item.get("email") and "@" in item.get("email", ""))
626
+
627
+ return [{
628
+ "json": {
629
+ **item,
630
+ "valid": is_valid,
631
+ "validated_at": datetime.now().isoformat()
632
+ }
633
+ }]
634
+ ```
635
+
636
+ ### Example 4: Extract Nested Data
637
+
638
+ ```python
639
+ response = _input.first()["json"]
640
+
641
+ # Navigate nested structure
642
+ users = response.get("data", {}).get("users", [])
643
+
644
+ return [
645
+ {
646
+ "json": {
647
+ "id": user.get("id"),
648
+ "name": user.get("profile", {}).get("name", "Unknown"),
649
+ "email": user.get("contact", {}).get("email", "no-email")
650
+ }
651
+ }
652
+ for user in users
653
+ ]
654
+ ```
655
+
656
+ ---
657
+
658
+ ## Pattern 3: \_input.item - Current Item (Each Item Mode)
659
+
660
+ **Usage**: Common in "Run Once for Each Item" mode
661
+
662
+ **When to use:**
663
+
664
+ - Mode is set to "Run Once for Each Item"
665
+ - Need to process items independently
666
+ - Per-item API calls or validations
667
+
668
+ **IMPORTANT**: Only use in "Each Item" mode. Will be undefined in "All Items" mode.
669
+
670
+ ### Basic Usage
671
+
672
+ ```python
673
+ # In "Run Once for Each Item" mode
674
+ current_item = _input.item
675
+ data = current_item["json"]
676
+
677
+ print(f"Processing item: {data.get('id')}")
678
+
679
+ return [{
680
+ "json": {
681
+ **data,
682
+ "processed": True
683
+ }
684
+ }]
685
+ ```
686
+
687
+ ### Example 1: Add Processing Metadata
688
+
689
+ ```python
690
+ item = _input.item
691
+
692
+ return [{
693
+ "json": {
694
+ **item["json"],
695
+ "processed": True,
696
+ "processed_at": datetime.now().isoformat(),
697
+ "processing_duration": random.random() * 1000 # Simulated
698
+ }
699
+ }]
700
+ ```
701
+
702
+ ### Example 2: Per-Item Validation
703
+
704
+ ```python
705
+ item = _input.item
706
+ data = item["json"]
707
+
708
+ # Validate this specific item
709
+ errors = []
710
+
711
+ if not data.get("email"):
712
+ errors.append("Email required")
713
+ if not data.get("name"):
714
+ errors.append("Name required")
715
+ if data.get("age") and data["age"] < 18:
716
+ errors.append("Must be 18+")
717
+
718
+ return [{
719
+ "json": {
720
+ **data,
721
+ "valid": len(errors) == 0,
722
+ "errors": errors if errors else None
723
+ }
724
+ }]
725
+ ```
726
+
727
+ ### Example 3: Conditional Processing
728
+
729
+ ```python
730
+ item = _input.item
731
+ data = item["json"]
732
+
733
+ # Process based on item type
734
+ if data.get("type") == "premium":
735
+ return [{
736
+ "json": {
737
+ **data,
738
+ "discount": 0.20,
739
+ "tier": "premium"
740
+ }
741
+ }]
742
+ else:
743
+ return [{
744
+ "json": {
745
+ **data,
746
+ "discount": 0.05,
747
+ "tier": "standard"
748
+ }
749
+ }]
750
+ ```
751
+
752
+ ---
753
+
754
+ ## Pattern 4: \_node - Reference Other Nodes
755
+
756
+ **Usage**: Less common, but powerful for specific scenarios
757
+
758
+ **When to use:**
759
+
760
+ - Need data from specific named node
761
+ - Combining data from multiple nodes
762
+
763
+ ### Basic Usage
764
+
765
+ ```python
766
+ # Get output from specific node
767
+ webhook_data = _node["Webhook"]["json"]
768
+ api_data = _node["HTTP Request"]["json"]
769
+
770
+ return [{
771
+ "json": {
772
+ "from_webhook": webhook_data,
773
+ "from_api": api_data
774
+ }
775
+ }]
776
+ ```
777
+
778
+ ### Example 1: Combine Multiple Sources
779
+
780
+ ```python
781
+ # Reference multiple nodes
782
+ webhook = _node["Webhook"]["json"]
783
+ database = _node["Postgres"]["json"]
784
+ api = _node["HTTP Request"]["json"]
785
+
786
+ return [{
787
+ "json": {
788
+ "combined": {
789
+ "webhook": webhook.get("body", {}),
790
+ "db_records": len(database) if isinstance(database, list) else 1,
791
+ "api_response": api.get("status")
792
+ },
793
+ "processed_at": datetime.now().isoformat()
794
+ }
795
+ }]
796
+ ```
797
+
798
+ ### Example 2: Compare Across Nodes
799
+
800
+ ```python
801
+ old_data = _node["Get Old Data"]["json"]
802
+ new_data = _node["Get New Data"]["json"]
803
+
804
+ # Simple comparison
805
+ changes = {
806
+ "added": [n for n in new_data if n.get("id") not in [o.get("id") for o in old_data]],
807
+ "removed": [o for o in old_data if o.get("id") not in [n.get("id") for n in new_data]]
808
+ }
809
+
810
+ return [{
811
+ "json": {
812
+ "changes": changes,
813
+ "summary": {
814
+ "added": len(changes["added"]),
815
+ "removed": len(changes["removed"])
816
+ }
817
+ }
818
+ }]
819
+ ```
820
+
821
+ ---
822
+
823
+ ## Critical: Webhook Data Structure
824
+
825
+ **MOST COMMON MISTAKE**: Forgetting webhook data is nested under `["body"]`
826
+
827
+ ### The Problem
828
+
829
+ Webhook node wraps all incoming data under a `"body"` property.
830
+
831
+ ### Structure
832
+
833
+ ```python
834
+ # Webhook node output structure:
835
+ {
836
+ "headers": {
837
+ "content-type": "application/json",
838
+ "user-agent": "..."
839
+ },
840
+ "params": {},
841
+ "query": {},
842
+ "body": {
843
+ # <- YOUR DATA IS HERE
844
+ "name": "Alice",
845
+ "email": "alice@example.com",
846
+ "message": "Hello!"
847
+ }
848
+ }
849
+ ```
850
+
851
+ ### Wrong vs Right
852
+
853
+ ```python
854
+ # WRONG: Trying to access directly
855
+ name = _json["name"] # KeyError!
856
+ email = _json["email"] # KeyError!
857
+
858
+ # CORRECT: Access via ["body"]
859
+ name = _json["body"]["name"] # "Alice"
860
+ email = _json["body"]["email"] # "alice@example.com"
861
+
862
+ # SAFER: Use .get() for safe access
863
+ webhook_data = _json.get("body", {})
864
+ name = webhook_data.get("name") # None if missing
865
+ email = webhook_data.get("email", "no-email") # Default value
866
+ ```
867
+
868
+ ### Example: Full Webhook Processing
869
+
870
+ ```python
871
+ # Get webhook data from previous node
872
+ webhook_output = _input.first()["json"]
873
+
874
+ # Access the actual payload
875
+ payload = webhook_output.get("body", {})
876
+
877
+ # Access headers if needed
878
+ content_type = webhook_output.get("headers", {}).get("content-type")
879
+
880
+ # Access query parameters if needed
881
+ api_key = webhook_output.get("query", {}).get("api_key")
882
+
883
+ # Process the actual data
884
+ return [{
885
+ "json": {
886
+ # Data from webhook body
887
+ "user_name": payload.get("name"),
888
+ "user_email": payload.get("email"),
889
+ "message": payload.get("message"),
890
+
891
+ # Metadata
892
+ "received_at": datetime.now().isoformat(),
893
+ "content_type": content_type,
894
+ "authenticated": bool(api_key)
895
+ }
896
+ }]
897
+ ```
898
+
899
+ ### POST Data, Query Params, and Headers
900
+
901
+ ```python
902
+ webhook = _input.first()["json"]
903
+
904
+ return [{
905
+ "json": {
906
+ # POST body data
907
+ "form_data": webhook.get("body", {}),
908
+
909
+ # Query parameters (?key=value)
910
+ "query_params": webhook.get("query", {}),
911
+
912
+ # HTTP headers
913
+ "user_agent": webhook.get("headers", {}).get("user-agent"),
914
+ "content_type": webhook.get("headers", {}).get("content-type"),
915
+
916
+ # Request metadata
917
+ "method": webhook.get("method"), # POST, GET, etc.
918
+ "url": webhook.get("url")
919
+ }
920
+ }]
921
+ ```
922
+
923
+ ---
924
+
925
+ ## Choosing the Right Pattern
926
+
927
+ ### Decision Tree
928
+
929
+ ```
930
+ Do you need ALL items from previous node?
931
+ |- YES -> Use _input.all()
932
+ |
933
+ \- NO -> Do you need just the FIRST item?
934
+ |- YES -> Use _input.first()
935
+ |
936
+ \- NO -> Are you in "Each Item" mode?
937
+ |- YES -> Use _input.item
938
+ |
939
+ \- NO -> Do you need specific node data?
940
+ |- YES -> Use _node["NodeName"]
941
+ \- NO -> Use _input.first() (default)
942
+ ```
943
+
944
+ ### Quick Reference Table
945
+
946
+ | Scenario | Use This | Example |
947
+ | -------------------------- | ---------------- | ------------------------------------------------ |
948
+ | Sum all amounts | `_input.all()` | `sum(i["json"].get("amount", 0) for i in items)` |
949
+ | Get API response | `_input.first()` | `_input.first()["json"].get("data")` |
950
+ | Process each independently | `_input.item` | `_input.item["json"]` (Each Item mode) |
951
+ | Combine two nodes | `_node["Name"]` | `_node["API"]["json"]` |
952
+ | Filter list | `_input.all()` | `[i for i in items if i["json"].get("active")]` |
953
+ | Transform single object | `_input.first()` | `{**_input.first()["json"], "new": True}` |
954
+ | Webhook data | `_input.first()` | `_input.first()["json"]["body"]` |
955
+
956
+ ---
957
+
958
+ ## Common Data Access Mistakes
959
+
960
+ ### Mistake 1: Using \_json Without Context
961
+
962
+ ```python
963
+ # RISKY: _json is ambiguous
964
+ value = _json["field"]
965
+
966
+ # CLEAR: Be explicit
967
+ value = _input.first()["json"]["field"]
968
+ ```
969
+
970
+ ### Mistake 2: Forgetting ["json"] Property
971
+
972
+ ```python
973
+ # WRONG: Trying to access fields on item dictionary
974
+ items = _input.all()
975
+ names = [item["name"] for item in items] # KeyError!
976
+
977
+ # CORRECT: Access via ["json"]
978
+ names = [item["json"]["name"] for item in items]
979
+ ```
980
+
981
+ ### Mistake 3: Using \_input.item in All Items Mode
982
+
983
+ ```python
984
+ # WRONG: _input.item is None in "All Items" mode
985
+ data = _input.item["json"] # AttributeError!
986
+
987
+ # CORRECT: Use appropriate method
988
+ data = _input.first()["json"] # Or _input.all()
989
+ ```
990
+
991
+ ### Mistake 4: Not Handling Empty Lists
992
+
993
+ ```python
994
+ # WRONG: Crashes if no items
995
+ first = _input.all()[0]["json"] # IndexError!
996
+
997
+ # CORRECT: Check length first
998
+ items = _input.all()
999
+ if items:
1000
+ first = items[0]["json"]
1001
+ else:
1002
+ return []
1003
+
1004
+ # ALSO CORRECT: Use _input.first()
1005
+ first = _input.first()["json"] # Built-in safety
1006
+ ```
1007
+
1008
+ ### Mistake 5: Direct Dictionary Access (KeyError)
1009
+
1010
+ ```python
1011
+ # RISKY: Crashes if key missing
1012
+ value = item["json"]["field"] # KeyError!
1013
+
1014
+ # SAFE: Use .get()
1015
+ value = item["json"].get("field", "default")
1016
+ ```
1017
+
1018
+ ---
1019
+
1020
+ ## Advanced Data Access Patterns
1021
+
1022
+ ### Pattern: Safe Nested Access
1023
+
1024
+ ```python
1025
+ # Deep nested access with .get()
1026
+ value = (
1027
+ _input.first()["json"]
1028
+ .get("level1", {})
1029
+ .get("level2", {})
1030
+ .get("level3", "default")
1031
+ )
1032
+ ```
1033
+
1034
+ ### Pattern: List Comprehension with Filtering
1035
+
1036
+ ```python
1037
+ items = _input.all()
1038
+
1039
+ # Filter and transform in one step
1040
+ result = [
1041
+ {
1042
+ "json": {
1043
+ "id": item["json"]["id"],
1044
+ "name": item["json"]["name"].upper()
1045
+ }
1046
+ }
1047
+ for item in items
1048
+ if item["json"].get("active") and item["json"].get("verified")
1049
+ ]
1050
+
1051
+ return result
1052
+ ```
1053
+
1054
+ ### Pattern: Dictionary Comprehension
1055
+
1056
+ ```python
1057
+ items = _input.all()
1058
+
1059
+ # Create lookup dictionary
1060
+ lookup = {
1061
+ item["json"]["id"]: item["json"]
1062
+ for item in items
1063
+ if "id" in item["json"]
1064
+ }
1065
+
1066
+ return [{"json": lookup}]
1067
+ ```
1068
+
1069
+ ---
1070
+
1071
+ # Standard Library Reference - Python Code Node
1072
+
1073
+ Complete guide to available Python standard library modules in n8n Code nodes.
1074
+
1075
+ ---
1076
+
1077
+ ## Critical Limitation
1078
+
1079
+ **NO EXTERNAL LIBRARIES AVAILABLE**
1080
+
1081
+ Python Code nodes in n8n have **ONLY** the Python standard library. No pip packages.
1082
+
1083
+ ```python
1084
+ # NOT AVAILABLE - Will cause ModuleNotFoundError
1085
+ import requests # No HTTP library!
1086
+ import pandas # No data analysis!
1087
+ import numpy # No numerical computing!
1088
+ import bs4 # No web scraping!
1089
+ import selenium # No browser automation!
1090
+ import psycopg2 # No database drivers!
1091
+ import pymongo # No MongoDB!
1092
+ import sqlalchemy # No ORMs!
1093
+
1094
+ # AVAILABLE - Standard library only
1095
+ import json
1096
+ import datetime
1097
+ import re
1098
+ import base64
1099
+ import hashlib
1100
+ import urllib.parse
1101
+ import urllib.request
1102
+ import math
1103
+ import random
1104
+ import statistics
1105
+ ```
1106
+
1107
+ **Recommendation**: Use **JavaScript** for 95% of use cases. JavaScript has more capabilities in n8n.
1108
+
1109
+ ---
1110
+
1111
+ ## Available Modules
1112
+
1113
+ ### Priority 1: Most Useful (Use These)
1114
+
1115
+ 1. **json** - JSON parsing and generation
1116
+ 2. **datetime** - Date and time operations
1117
+ 3. **re** - Regular expressions
1118
+ 4. **base64** - Base64 encoding/decoding
1119
+ 5. **hashlib** - Hashing (MD5, SHA256, etc.)
1120
+ 6. **urllib.parse** - URL parsing and encoding
1121
+
1122
+ ### Priority 2: Moderately Useful
1123
+
1124
+ 7. **math** - Mathematical functions
1125
+ 8. **random** - Random number generation
1126
+ 9. **statistics** - Statistical functions
1127
+ 10. **collections** - Specialized data structures
1128
+
1129
+ ### Priority 3: Occasionally Useful
1130
+
1131
+ 11. **itertools** - Iterator tools
1132
+ 12. **functools** - Higher-order functions
1133
+ 13. **operator** - Standard operators as functions
1134
+ 14. **string** - String constants and templates
1135
+ 15. **textwrap** - Text wrapping utilities
1136
+
1137
+ ---
1138
+
1139
+ ## Module 1: json - JSON Operations
1140
+
1141
+ **Most common module** - Parse and generate JSON data.
1142
+
1143
+ ### Parse JSON String
1144
+
1145
+ ```python
1146
+ import json
1147
+
1148
+ # Parse JSON string to Python dict
1149
+ json_string = '{"name": "Alice", "age": 30}'
1150
+ data = json.loads(json_string)
1151
+
1152
+ return [{
1153
+ "json": {
1154
+ "name": data["name"],
1155
+ "age": data["age"],
1156
+ "parsed": True
1157
+ }
1158
+ }]
1159
+ ```
1160
+
1161
+ ### Generate JSON String
1162
+
1163
+ ```python
1164
+ import json
1165
+
1166
+ # Convert Python dict to JSON string
1167
+ data = {
1168
+ "users": [
1169
+ {"id": 1, "name": "Alice"},
1170
+ {"id": 2, "name": "Bob"}
1171
+ ],
1172
+ "total": 2
1173
+ }
1174
+
1175
+ json_string = json.dumps(data, indent=2)
1176
+
1177
+ return [{
1178
+ "json": {
1179
+ "json_output": json_string,
1180
+ "length": len(json_string)
1181
+ }
1182
+ }]
1183
+ ```
1184
+
1185
+ ### Handle JSON Errors
1186
+
1187
+ ```python
1188
+ import json
1189
+
1190
+ webhook_data = _input.first()["json"]["body"]
1191
+ json_string = webhook_data.get("data", "")
1192
+
1193
+ try:
1194
+ parsed = json.loads(json_string)
1195
+ status = "valid"
1196
+ error = None
1197
+ except json.JSONDecodeError as e:
1198
+ parsed = None
1199
+ status = "invalid"
1200
+ error = str(e)
1201
+
1202
+ return [{
1203
+ "json": {
1204
+ "status": status,
1205
+ "data": parsed,
1206
+ "error": error
1207
+ }
1208
+ }]
1209
+ ```
1210
+
1211
+ ### Pretty Print JSON
1212
+
1213
+ ```python
1214
+ import json
1215
+
1216
+ # Format JSON with indentation
1217
+ data = _input.first()["json"]
1218
+
1219
+ pretty_json = json.dumps(data, indent=2, sort_keys=True)
1220
+
1221
+ return [{
1222
+ "json": {
1223
+ "formatted": pretty_json
1224
+ }
1225
+ }]
1226
+ ```
1227
+
1228
+ ---
1229
+
1230
+ ## Module 2: datetime - Date and Time
1231
+
1232
+ **Very common** - Date parsing, formatting, calculations.
1233
+
1234
+ ### Current Date and Time
1235
+
1236
+ ```python
1237
+ from datetime import datetime
1238
+
1239
+ now = datetime.now()
1240
+
1241
+ return [{
1242
+ "json": {
1243
+ "timestamp": now.isoformat(),
1244
+ "date": now.strftime("%Y-%m-%d"),
1245
+ "time": now.strftime("%H:%M:%S"),
1246
+ "formatted": now.strftime("%B %d, %Y at %I:%M %p")
1247
+ }
1248
+ }]
1249
+ ```
1250
+
1251
+ ### Parse Date String
1252
+
1253
+ ```python
1254
+ from datetime import datetime
1255
+
1256
+ date_string = "2025-01-15T14:30:00"
1257
+ dt = datetime.fromisoformat(date_string)
1258
+
1259
+ return [{
1260
+ "json": {
1261
+ "year": dt.year,
1262
+ "month": dt.month,
1263
+ "day": dt.day,
1264
+ "hour": dt.hour,
1265
+ "weekday": dt.strftime("%A")
1266
+ }
1267
+ }]
1268
+ ```
1269
+
1270
+ ### Date Calculations
1271
+
1272
+ ```python
1273
+ from datetime import datetime, timedelta
1274
+
1275
+ now = datetime.now()
1276
+
1277
+ # Calculate future/past dates
1278
+ tomorrow = now + timedelta(days=1)
1279
+ yesterday = now - timedelta(days=1)
1280
+ next_week = now + timedelta(weeks=1)
1281
+ one_hour_ago = now - timedelta(hours=1)
1282
+
1283
+ return [{
1284
+ "json": {
1285
+ "now": now.isoformat(),
1286
+ "tomorrow": tomorrow.isoformat(),
1287
+ "yesterday": yesterday.isoformat(),
1288
+ "next_week": next_week.isoformat(),
1289
+ "one_hour_ago": one_hour_ago.isoformat()
1290
+ }
1291
+ }]
1292
+ ```
1293
+
1294
+ ### Compare Dates
1295
+
1296
+ ```python
1297
+ from datetime import datetime
1298
+
1299
+ date1 = datetime(2025, 1, 15)
1300
+ date2 = datetime(2025, 1, 20)
1301
+
1302
+ # Calculate difference
1303
+ diff = date2 - date1
1304
+
1305
+ return [{
1306
+ "json": {
1307
+ "days_difference": diff.days,
1308
+ "seconds_difference": diff.total_seconds(),
1309
+ "date1_is_earlier": date1 < date2,
1310
+ "date2_is_later": date2 > date1
1311
+ }
1312
+ }]
1313
+ ```
1314
+
1315
+ ### Format Dates
1316
+
1317
+ ```python
1318
+ from datetime import datetime
1319
+
1320
+ dt = datetime.now()
1321
+
1322
+ return [{
1323
+ "json": {
1324
+ "iso": dt.isoformat(),
1325
+ "us_format": dt.strftime("%m/%d/%Y"),
1326
+ "eu_format": dt.strftime("%d/%m/%Y"),
1327
+ "long_format": dt.strftime("%A, %B %d, %Y"),
1328
+ "time_12h": dt.strftime("%I:%M %p"),
1329
+ "time_24h": dt.strftime("%H:%M:%S")
1330
+ }
1331
+ }]
1332
+ ```
1333
+
1334
+ ---
1335
+
1336
+ ## Module 3: re - Regular Expressions
1337
+
1338
+ **Common** - Pattern matching, text extraction, validation.
1339
+
1340
+ ### Pattern Matching
1341
+
1342
+ ```python
1343
+ import re
1344
+
1345
+ text = "Email: alice@example.com, Phone: 555-1234"
1346
+
1347
+ # Find email
1348
+ email_match = re.search(r'\b[\w.-]+@[\w.-]+\.\w+\b', text)
1349
+ email = email_match.group(0) if email_match else None
1350
+
1351
+ # Find phone
1352
+ phone_match = re.search(r'\d{3}-\d{4}', text)
1353
+ phone = phone_match.group(0) if phone_match else None
1354
+
1355
+ return [{
1356
+ "json": {
1357
+ "email": email,
1358
+ "phone": phone
1359
+ }
1360
+ }]
1361
+ ```
1362
+
1363
+ ### Extract All Matches
1364
+
1365
+ ```python
1366
+ import re
1367
+
1368
+ text = "Tags: #python #automation #workflow #n8n"
1369
+
1370
+ # Find all hashtags
1371
+ hashtags = re.findall(r'#(\w+)', text)
1372
+
1373
+ return [{
1374
+ "json": {
1375
+ "tags": hashtags,
1376
+ "count": len(hashtags)
1377
+ }
1378
+ }]
1379
+ ```
1380
+
1381
+ ### Replace Patterns
1382
+
1383
+ ```python
1384
+ import re
1385
+
1386
+ text = "Price: $99.99, Discount: $10.00"
1387
+
1388
+ # Remove dollar signs
1389
+ cleaned = re.sub(r'\$', '', text)
1390
+
1391
+ # Replace multiple spaces with single space
1392
+ normalized = re.sub(r'\s+', ' ', cleaned)
1393
+
1394
+ return [{
1395
+ "json": {
1396
+ "original": text,
1397
+ "cleaned": cleaned,
1398
+ "normalized": normalized
1399
+ }
1400
+ }]
1401
+ ```
1402
+
1403
+ ### Validate Format
1404
+
1405
+ ```python
1406
+ import re
1407
+
1408
+ email = _input.first()["json"]["body"].get("email", "")
1409
+
1410
+ # Email validation pattern
1411
+ email_pattern = r'^[\w.-]+@[\w.-]+\.\w+$'
1412
+ is_valid = bool(re.match(email_pattern, email))
1413
+
1414
+ return [{
1415
+ "json": {
1416
+ "email": email,
1417
+ "valid": is_valid
1418
+ }
1419
+ }]
1420
+ ```
1421
+
1422
+ ### Split on Pattern
1423
+
1424
+ ```python
1425
+ import re
1426
+
1427
+ text = "apple,banana;orange|grape"
1428
+
1429
+ # Split on multiple delimiters
1430
+ items = re.split(r'[,;|]', text)
1431
+
1432
+ # Clean up whitespace
1433
+ items = [item.strip() for item in items]
1434
+
1435
+ return [{
1436
+ "json": {
1437
+ "items": items,
1438
+ "count": len(items)
1439
+ }
1440
+ }]
1441
+ ```
1442
+
1443
+ ---
1444
+
1445
+ ## Module 4: base64 - Encoding/Decoding
1446
+
1447
+ **Common** - Encode binary data, API authentication.
1448
+
1449
+ ### Encode String to Base64
1450
+
1451
+ ```python
1452
+ import base64
1453
+
1454
+ text = "Hello, World!"
1455
+
1456
+ # Encode to base64
1457
+ encoded_bytes = base64.b64encode(text.encode('utf-8'))
1458
+ encoded_string = encoded_bytes.decode('utf-8')
1459
+
1460
+ return [{
1461
+ "json": {
1462
+ "original": text,
1463
+ "encoded": encoded_string
1464
+ }
1465
+ }]
1466
+ ```
1467
+
1468
+ ### Decode Base64 to String
1469
+
1470
+ ```python
1471
+ import base64
1472
+
1473
+ encoded = "SGVsbG8sIFdvcmxkIQ=="
1474
+
1475
+ # Decode from base64
1476
+ decoded_bytes = base64.b64decode(encoded)
1477
+ decoded_string = decoded_bytes.decode('utf-8')
1478
+
1479
+ return [{
1480
+ "json": {
1481
+ "encoded": encoded,
1482
+ "decoded": decoded_string
1483
+ }
1484
+ }]
1485
+ ```
1486
+
1487
+ ### Basic Auth Header
1488
+
1489
+ ```python
1490
+ import base64
1491
+
1492
+ username = "admin"
1493
+ password = "secret123"
1494
+
1495
+ # Create Basic Auth header
1496
+ credentials = f"{username}:{password}"
1497
+ encoded = base64.b64encode(credentials.encode('utf-8')).decode('utf-8')
1498
+ auth_header = f"Basic {encoded}"
1499
+
1500
+ return [{
1501
+ "json": {
1502
+ "authorization": auth_header
1503
+ }
1504
+ }]
1505
+ ```
1506
+
1507
+ ---
1508
+
1509
+ ## Module 5: hashlib - Hashing
1510
+
1511
+ **Common** - Generate checksums, hash passwords, create IDs.
1512
+
1513
+ ### MD5 Hash
1514
+
1515
+ ```python
1516
+ import hashlib
1517
+
1518
+ text = "Hello, World!"
1519
+
1520
+ # Generate MD5 hash
1521
+ md5_hash = hashlib.md5(text.encode('utf-8')).hexdigest()
1522
+
1523
+ return [{
1524
+ "json": {
1525
+ "original": text,
1526
+ "md5": md5_hash
1527
+ }
1528
+ }]
1529
+ ```
1530
+
1531
+ ### SHA256 Hash
1532
+
1533
+ ```python
1534
+ import hashlib
1535
+
1536
+ data = _input.first()["json"]["body"]
1537
+ text = data.get("password", "")
1538
+
1539
+ # Generate SHA256 hash (more secure than MD5)
1540
+ sha256_hash = hashlib.sha256(text.encode('utf-8')).hexdigest()
1541
+
1542
+ return [{
1543
+ "json": {
1544
+ "hashed": sha256_hash
1545
+ }
1546
+ }]
1547
+ ```
1548
+
1549
+ ### Generate Unique ID
1550
+
1551
+ ```python
1552
+ import hashlib
1553
+ from datetime import datetime
1554
+
1555
+ # Create unique ID from multiple values
1556
+ unique_string = f"{datetime.now().isoformat()}-{_json.get('user_id', 'unknown')}"
1557
+ unique_id = hashlib.sha256(unique_string.encode('utf-8')).hexdigest()[:16]
1558
+
1559
+ return [{
1560
+ "json": {
1561
+ "id": unique_id,
1562
+ "generated_at": datetime.now().isoformat()
1563
+ }
1564
+ }]
1565
+ ```
1566
+
1567
+ ---
1568
+
1569
+ ## Module 6: urllib.parse - URL Operations
1570
+
1571
+ **Common** - Parse URLs, encode parameters.
1572
+
1573
+ ### Parse URL
1574
+
1575
+ ```python
1576
+ from urllib.parse import urlparse
1577
+
1578
+ url = "https://example.com/path?key=value&foo=bar#section"
1579
+
1580
+ parsed = urlparse(url)
1581
+
1582
+ return [{
1583
+ "json": {
1584
+ "scheme": parsed.scheme, # "https"
1585
+ "netloc": parsed.netloc, # "example.com"
1586
+ "path": parsed.path, # "/path"
1587
+ "query": parsed.query, # "key=value&foo=bar"
1588
+ "fragment": parsed.fragment # "section"
1589
+ }
1590
+ }]
1591
+ ```
1592
+
1593
+ ### URL Encode Parameters
1594
+
1595
+ ```python
1596
+ from urllib.parse import urlencode
1597
+
1598
+ params = {
1599
+ "name": "Alice Smith",
1600
+ "email": "alice@example.com",
1601
+ "message": "Hello, World!"
1602
+ }
1603
+
1604
+ # Encode parameters for URL
1605
+ encoded = urlencode(params)
1606
+
1607
+ return [{
1608
+ "json": {
1609
+ "query_string": encoded,
1610
+ "full_url": f"https://api.example.com/submit?{encoded}"
1611
+ }
1612
+ }]
1613
+ ```
1614
+
1615
+ ### Parse Query String
1616
+
1617
+ ```python
1618
+ from urllib.parse import parse_qs
1619
+
1620
+ query_string = "name=Alice&age=30&tags=python&tags=n8n"
1621
+
1622
+ # Parse query string
1623
+ params = parse_qs(query_string)
1624
+
1625
+ return [{
1626
+ "json": {
1627
+ "name": params.get("name", [""])[0],
1628
+ "age": int(params.get("age", ["0"])[0]),
1629
+ "tags": params.get("tags", [])
1630
+ }
1631
+ }]
1632
+ ```
1633
+
1634
+ ### URL Encode/Decode Strings
1635
+
1636
+ ```python
1637
+ from urllib.parse import quote, unquote
1638
+
1639
+ text = "Hello, World! 你好"
1640
+
1641
+ # URL encode
1642
+ encoded = quote(text)
1643
+
1644
+ # URL decode
1645
+ decoded = unquote(encoded)
1646
+
1647
+ return [{
1648
+ "json": {
1649
+ "original": text,
1650
+ "encoded": encoded,
1651
+ "decoded": decoded
1652
+ }
1653
+ }]
1654
+ ```
1655
+
1656
+ ---
1657
+
1658
+ ## Module 7: math - Mathematical Operations
1659
+
1660
+ **Moderately useful** - Advanced math functions.
1661
+
1662
+ ### Basic Math Functions
1663
+
1664
+ ```python
1665
+ import math
1666
+
1667
+ number = 16.7
1668
+
1669
+ return [{
1670
+ "json": {
1671
+ "ceiling": math.ceil(number), # 17
1672
+ "floor": math.floor(number), # 16
1673
+ "rounded": round(number), # 17
1674
+ "square_root": math.sqrt(16), # 4.0
1675
+ "power": math.pow(2, 3), # 8.0
1676
+ "absolute": math.fabs(-5.5) # 5.5
1677
+ }
1678
+ }]
1679
+ ```
1680
+
1681
+ ### Trigonometry
1682
+
1683
+ ```python
1684
+ import math
1685
+
1686
+ angle_degrees = 45
1687
+ angle_radians = math.radians(angle_degrees)
1688
+
1689
+ return [{
1690
+ "json": {
1691
+ "sine": math.sin(angle_radians),
1692
+ "cosine": math.cos(angle_radians),
1693
+ "tangent": math.tan(angle_radians),
1694
+ "pi": math.pi,
1695
+ "e": math.e
1696
+ }
1697
+ }]
1698
+ ```
1699
+
1700
+ ### Logarithms
1701
+
1702
+ ```python
1703
+ import math
1704
+
1705
+ number = 100
1706
+
1707
+ return [{
1708
+ "json": {
1709
+ "log10": math.log10(number), # 2.0
1710
+ "natural_log": math.log(number), # 4.605...
1711
+ "log2": math.log2(number) # 6.644...
1712
+ }
1713
+ }]
1714
+ ```
1715
+
1716
+ ---
1717
+
1718
+ ## Module 8: random - Random Numbers
1719
+
1720
+ **Moderately useful** - Generate random data, sampling.
1721
+
1722
+ ### Random Numbers
1723
+
1724
+ ```python
1725
+ import random
1726
+
1727
+ return [{
1728
+ "json": {
1729
+ "random_float": random.random(), # 0.0 to 1.0
1730
+ "random_int": random.randint(1, 100), # 1 to 100
1731
+ "random_range": random.randrange(0, 100, 5) # 0, 5, 10, ..., 95
1732
+ }
1733
+ }]
1734
+ ```
1735
+
1736
+ ### Random Choice
1737
+
1738
+ ```python
1739
+ import random
1740
+
1741
+ colors = ["red", "green", "blue", "yellow"]
1742
+ users = [{"id": 1, "name": "Alice"}, {"id": 2, "name": "Bob"}]
1743
+
1744
+ return [{
1745
+ "json": {
1746
+ "random_color": random.choice(colors),
1747
+ "random_user": random.choice(users)
1748
+ }
1749
+ }]
1750
+ ```
1751
+
1752
+ ### Shuffle List
1753
+
1754
+ ```python
1755
+ import random
1756
+
1757
+ items = [1, 2, 3, 4, 5]
1758
+ shuffled = items.copy()
1759
+ random.shuffle(shuffled)
1760
+
1761
+ return [{
1762
+ "json": {
1763
+ "original": items,
1764
+ "shuffled": shuffled
1765
+ }
1766
+ }]
1767
+ ```
1768
+
1769
+ ### Random Sample
1770
+
1771
+ ```python
1772
+ import random
1773
+
1774
+ items = list(range(1, 101))
1775
+
1776
+ # Get 10 random items without replacement
1777
+ sample = random.sample(items, 10)
1778
+
1779
+ return [{
1780
+ "json": {
1781
+ "sample": sample,
1782
+ "count": len(sample)
1783
+ }
1784
+ }]
1785
+ ```
1786
+
1787
+ ---
1788
+
1789
+ ## Module 9: statistics - Statistical Functions
1790
+
1791
+ **Moderately useful** - Calculate stats from data.
1792
+
1793
+ ### Basic Statistics
1794
+
1795
+ ```python
1796
+ import statistics
1797
+
1798
+ numbers = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100]
1799
+
1800
+ return [{
1801
+ "json": {
1802
+ "mean": statistics.mean(numbers), # 55.0
1803
+ "median": statistics.median(numbers), # 55.0
1804
+ "mode": statistics.mode([1, 2, 2, 3]), # 2
1805
+ "stdev": statistics.stdev(numbers), # 30.28...
1806
+ "variance": statistics.variance(numbers) # 916.67...
1807
+ }
1808
+ }]
1809
+ ```
1810
+
1811
+ ### Aggregate from Items
1812
+
1813
+ ```python
1814
+ import statistics
1815
+
1816
+ all_items = _input.all()
1817
+
1818
+ # Extract amounts
1819
+ amounts = [item["json"].get("amount", 0) for item in all_items]
1820
+
1821
+ if amounts:
1822
+ return [{
1823
+ "json": {
1824
+ "count": len(amounts),
1825
+ "total": sum(amounts),
1826
+ "average": statistics.mean(amounts),
1827
+ "median": statistics.median(amounts),
1828
+ "min": min(amounts),
1829
+ "max": max(amounts),
1830
+ "range": max(amounts) - min(amounts)
1831
+ }
1832
+ }]
1833
+ else:
1834
+ return [{"json": {"error": "No data"}}]
1835
+ ```
1836
+
1837
+ ---
1838
+
1839
+ ## Workarounds for Missing Libraries
1840
+
1841
+ ### HTTP Requests (No requests library)
1842
+
1843
+ ```python
1844
+ # Can't use requests library
1845
+ # import requests # ModuleNotFoundError!
1846
+
1847
+ # Use HTTP Request node instead
1848
+ # Add HTTP Request node BEFORE Code node
1849
+ # Access the response in Code node
1850
+
1851
+ response_data = _input.first()["json"]
1852
+
1853
+ return [{
1854
+ "json": {
1855
+ "status": response_data.get("status"),
1856
+ "data": response_data.get("body"),
1857
+ "processed": True
1858
+ }
1859
+ }]
1860
+ ```
1861
+
1862
+ ### Data Processing (No pandas)
1863
+
1864
+ ```python
1865
+ # Can't use pandas
1866
+ # import pandas as pd # ModuleNotFoundError!
1867
+
1868
+ # Use Python's built-in list comprehensions
1869
+ all_items = _input.all()
1870
+
1871
+ # Filter
1872
+ active_items = [
1873
+ item for item in all_items
1874
+ if item["json"].get("status") == "active"
1875
+ ]
1876
+
1877
+ # Group by
1878
+ from collections import defaultdict
1879
+ grouped = defaultdict(list)
1880
+
1881
+ for item in all_items:
1882
+ category = item["json"].get("category", "other")
1883
+ grouped[category].append(item["json"])
1884
+
1885
+ # Aggregate
1886
+ import statistics
1887
+ amounts = [item["json"].get("amount", 0) for item in all_items]
1888
+ total = sum(amounts)
1889
+ average = statistics.mean(amounts) if amounts else 0
1890
+
1891
+ return [{
1892
+ "json": {
1893
+ "active_count": len(active_items),
1894
+ "grouped": dict(grouped),
1895
+ "total": total,
1896
+ "average": average
1897
+ }
1898
+ }]
1899
+ ```
1900
+
1901
+ ### Database Operations (No drivers)
1902
+
1903
+ ```python
1904
+ # Can't use database drivers
1905
+ # import psycopg2 # ModuleNotFoundError!
1906
+ # import pymongo # ModuleNotFoundError!
1907
+
1908
+ # Use n8n database nodes instead
1909
+ # Add Postgres/MySQL/MongoDB node BEFORE Code node
1910
+ # Process results in Code node
1911
+
1912
+ db_results = _input.first()["json"]
1913
+
1914
+ return [{
1915
+ "json": {
1916
+ "record_count": len(db_results) if isinstance(db_results, list) else 1,
1917
+ "processed": True
1918
+ }
1919
+ }]
1920
+ ```
1921
+
1922
+ ---
1923
+
1924
+ ## Complete Standard Library List
1925
+
1926
+ **Available** (commonly useful):
1927
+
1928
+ - json
1929
+ - datetime, time
1930
+ - re
1931
+ - base64
1932
+ - hashlib
1933
+ - urllib.parse, urllib.request, urllib.error
1934
+ - math
1935
+ - random
1936
+ - statistics
1937
+ - collections (defaultdict, Counter, namedtuple)
1938
+ - itertools
1939
+ - functools
1940
+ - operator
1941
+ - string
1942
+ - textwrap
1943
+
1944
+ **Available** (less common):
1945
+
1946
+ - os.path (path operations only)
1947
+ - copy
1948
+ - typing
1949
+ - enum
1950
+ - decimal
1951
+ - fractions
1952
+
1953
+ **NOT Available** (external libraries):
1954
+
1955
+ - requests (HTTP)
1956
+ - pandas (data analysis)
1957
+ - numpy (numerical computing)
1958
+ - bs4/beautifulsoup4 (HTML parsing)
1959
+ - selenium (browser automation)
1960
+ - psycopg2, pymongo, sqlalchemy (databases)
1961
+ - flask, fastapi (web frameworks)
1962
+ - pillow (image processing)
1963
+ - openpyxl, xlsxwriter (Excel)
1964
+
1965
+ ---
1966
+
1967
+ ## Standard Library Best Practices
1968
+
1969
+ ### 1. Use Standard Library When Possible
1970
+
1971
+ ```python
1972
+ # GOOD: Use standard library
1973
+ import json
1974
+ import datetime
1975
+ import re
1976
+
1977
+ data = _input.first()["json"]
1978
+ processed = json.loads(data.get("json_string", "{}"))
1979
+
1980
+ return [{"json": processed}]
1981
+ ```
1982
+
1983
+ ### 2. Fall Back to n8n Nodes
1984
+
1985
+ ```python
1986
+ # For operations requiring external libraries,
1987
+ # use n8n nodes instead:
1988
+ # - HTTP Request for API calls
1989
+ # - Postgres/MySQL for databases
1990
+ # - Extract from File for parsing
1991
+
1992
+ # Then process results in Code node
1993
+ result = _input.first()["json"]
1994
+ return [{"json": {"processed": result}}]
1995
+ ```
1996
+
1997
+ ### 3. Combine Multiple Modules
1998
+
1999
+ ```python
2000
+ import json
2001
+ import base64
2002
+ import hashlib
2003
+ from datetime import datetime
2004
+
2005
+ # Combine modules for complex operations
2006
+ data = _input.first()["json"]["body"]
2007
+
2008
+ # Hash sensitive data
2009
+ user_id = hashlib.sha256(data.get("email", "").encode()).hexdigest()[:16]
2010
+
2011
+ # Encode for storage
2012
+ encoded_data = base64.b64encode(json.dumps(data).encode()).decode()
2013
+
2014
+ return [{
2015
+ "json": {
2016
+ "user_id": user_id,
2017
+ "encoded_data": encoded_data,
2018
+ "timestamp": datetime.now().isoformat()
2019
+ }
2020
+ }]
2021
+ ```
2022
+
2023
+ ---
2024
+
2025
+ # Common Patterns - Python Code Node
2026
+
2027
+ Production-tested Python patterns for n8n Code nodes.
2028
+
2029
+ ---
2030
+
2031
+ ## Pattern Overview
2032
+
2033
+ These 10 patterns cover common n8n Code node scenarios using Python:
2034
+
2035
+ 1. **Multi-Source Data Aggregation** - Combine data from multiple nodes
2036
+ 2. **Regex-Based Filtering** - Filter items using pattern matching
2037
+ 3. **Markdown to Structured Data** - Parse markdown into structured format
2038
+ 4. **JSON Object Comparison** - Compare two JSON objects for changes
2039
+ 5. **CRM Data Transformation** - Transform CRM data to standard format
2040
+ 6. **Release Notes Processing** - Parse and categorize release notes
2041
+ 7. **Array Transformation** - Reshape arrays and extract fields
2042
+ 8. **Dictionary Lookup** - Create and use lookup dictionaries
2043
+ 9. **Top N Filtering** - Get top items by score/value
2044
+ 10. **String Aggregation** - Aggregate strings with formatting
2045
+
2046
+ ---
2047
+
2048
+ ## Pattern 1: Multi-Source Data Aggregation
2049
+
2050
+ **Use case**: Combine data from multiple sources (APIs, webhooks, databases).
2051
+
2052
+ **Scenario**: Aggregate news articles from multiple sources.
2053
+
2054
+ ### Implementation
2055
+
2056
+ ```python
2057
+ from datetime import datetime
2058
+
2059
+ all_items = _input.all()
2060
+ processed_articles = []
2061
+
2062
+ for item in all_items:
2063
+ source_name = item["json"].get("name", "Unknown")
2064
+ source_data = item["json"]
2065
+
2066
+ # Process Hacker News source
2067
+ if source_name == "Hacker News" and source_data.get("hits"):
2068
+ for hit in source_data["hits"]:
2069
+ processed_articles.append({
2070
+ "title": hit.get("title", "No title"),
2071
+ "url": hit.get("url", ""),
2072
+ "summary": hit.get("story_text") or "No summary",
2073
+ "source": "Hacker News",
2074
+ "score": hit.get("points", 0),
2075
+ "fetched_at": datetime.now().isoformat()
2076
+ })
2077
+
2078
+ # Process Reddit source
2079
+ elif source_name == "Reddit" and source_data.get("data"):
2080
+ for post in source_data["data"].get("children", []):
2081
+ post_data = post.get("data", {})
2082
+ processed_articles.append({
2083
+ "title": post_data.get("title", "No title"),
2084
+ "url": post_data.get("url", ""),
2085
+ "summary": post_data.get("selftext", "")[:200],
2086
+ "source": "Reddit",
2087
+ "score": post_data.get("score", 0),
2088
+ "fetched_at": datetime.now().isoformat()
2089
+ })
2090
+
2091
+ # Sort by score descending
2092
+ processed_articles.sort(key=lambda x: x["score"], reverse=True)
2093
+
2094
+ # Return as n8n items
2095
+ return [{"json": article} for article in processed_articles]
2096
+ ```
2097
+
2098
+ ### Key Techniques
2099
+
2100
+ - Process multiple data sources in one loop
2101
+ - Normalize different data structures
2102
+ - Use datetime for timestamps
2103
+ - Sort by criteria
2104
+ - Return properly formatted items
2105
+
2106
+ ---
2107
+
2108
+ ## Pattern 2: Regex-Based Filtering
2109
+
2110
+ **Use case**: Filter items based on pattern matching in text fields.
2111
+
2112
+ **Scenario**: Filter support tickets by priority keywords.
2113
+
2114
+ ### Implementation
2115
+
2116
+ ```python
2117
+ import re
2118
+
2119
+ all_items = _input.all()
2120
+ priority_tickets = []
2121
+
2122
+ # High priority keywords pattern
2123
+ high_priority_pattern = re.compile(
2124
+ r'\b(urgent|critical|emergency|asap|down|outage|broken)\b',
2125
+ re.IGNORECASE
2126
+ )
2127
+
2128
+ for item in all_items:
2129
+ ticket = item["json"]
2130
+
2131
+ # Check subject and description
2132
+ subject = ticket.get("subject", "")
2133
+ description = ticket.get("description", "")
2134
+ combined_text = f"{subject} {description}"
2135
+
2136
+ # Find matches
2137
+ matches = high_priority_pattern.findall(combined_text)
2138
+
2139
+ if matches:
2140
+ priority_tickets.append({
2141
+ "json": {
2142
+ **ticket,
2143
+ "priority": "high",
2144
+ "matched_keywords": list(set(matches)),
2145
+ "keyword_count": len(matches)
2146
+ }
2147
+ })
2148
+ else:
2149
+ priority_tickets.append({
2150
+ "json": {
2151
+ **ticket,
2152
+ "priority": "normal",
2153
+ "matched_keywords": [],
2154
+ "keyword_count": 0
2155
+ }
2156
+ })
2157
+
2158
+ # Sort by keyword count (most urgent first)
2159
+ priority_tickets.sort(key=lambda x: x["json"]["keyword_count"], reverse=True)
2160
+
2161
+ return priority_tickets
2162
+ ```
2163
+
2164
+ ### Key Techniques
2165
+
2166
+ - Use re.compile() for reusable patterns
2167
+ - re.IGNORECASE for case-insensitive matching
2168
+ - Combine multiple text fields for searching
2169
+ - Extract and deduplicate matches
2170
+ - Sort by priority indicators
2171
+
2172
+ ---
2173
+
2174
+ ## Pattern 3: Markdown to Structured Data
2175
+
2176
+ **Use case**: Parse markdown text into structured data.
2177
+
2178
+ **Scenario**: Extract tasks from markdown checklist.
2179
+
2180
+ ### Implementation
2181
+
2182
+ ```python
2183
+ import re
2184
+
2185
+ markdown_text = _input.first()["json"]["body"].get("markdown", "")
2186
+
2187
+ # Parse markdown checklist
2188
+ tasks = []
2189
+ lines = markdown_text.split("\n")
2190
+
2191
+ for line in lines:
2192
+ # Match: - [ ] Task or - [x] Task
2193
+ match = re.match(r'^\s*-\s*\[([ x])\]\s*(.+)$', line, re.IGNORECASE)
2194
+
2195
+ if match:
2196
+ checked = match.group(1).lower() == 'x'
2197
+ task_text = match.group(2).strip()
2198
+
2199
+ # Extract priority if present (e.g., [P1], [HIGH])
2200
+ priority_match = re.search(r'\[(P\d|HIGH|MEDIUM|LOW)\]', task_text, re.IGNORECASE)
2201
+ priority = priority_match.group(1).upper() if priority_match else "NORMAL"
2202
+
2203
+ # Remove priority tag from text
2204
+ clean_text = re.sub(r'\[(P\d|HIGH|MEDIUM|LOW)\]', '', task_text, flags=re.IGNORECASE).strip()
2205
+
2206
+ tasks.append({
2207
+ "text": clean_text,
2208
+ "completed": checked,
2209
+ "priority": priority,
2210
+ "original_line": line.strip()
2211
+ })
2212
+
2213
+ return [{
2214
+ "json": {
2215
+ "tasks": tasks,
2216
+ "total": len(tasks),
2217
+ "completed": sum(1 for t in tasks if t["completed"]),
2218
+ "pending": sum(1 for t in tasks if not t["completed"])
2219
+ }
2220
+ }]
2221
+ ```
2222
+
2223
+ ### Key Techniques
2224
+
2225
+ - Line-by-line parsing
2226
+ - Multiple regex patterns for extraction
2227
+ - Extract metadata from text
2228
+ - Calculate summary statistics
2229
+ - Return structured data
2230
+
2231
+ ---
2232
+
2233
+ ## Pattern 4: JSON Object Comparison
2234
+
2235
+ **Use case**: Compare two JSON objects to find differences.
2236
+
2237
+ **Scenario**: Compare old and new user profile data.
2238
+
2239
+ ### Implementation
2240
+
2241
+ ```python
2242
+ import json
2243
+
2244
+ all_items = _input.all()
2245
+
2246
+ # Assume first item is old data, second is new data
2247
+ old_data = all_items[0]["json"] if len(all_items) > 0 else {}
2248
+ new_data = all_items[1]["json"] if len(all_items) > 1 else {}
2249
+
2250
+ changes = {
2251
+ "added": {},
2252
+ "removed": {},
2253
+ "modified": {},
2254
+ "unchanged": {}
2255
+ }
2256
+
2257
+ # Find all unique keys
2258
+ all_keys = set(old_data.keys()) | set(new_data.keys())
2259
+
2260
+ for key in all_keys:
2261
+ old_value = old_data.get(key)
2262
+ new_value = new_data.get(key)
2263
+
2264
+ if key not in old_data:
2265
+ # Added field
2266
+ changes["added"][key] = new_value
2267
+ elif key not in new_data:
2268
+ # Removed field
2269
+ changes["removed"][key] = old_value
2270
+ elif old_value != new_value:
2271
+ # Modified field
2272
+ changes["modified"][key] = {
2273
+ "old": old_value,
2274
+ "new": new_value
2275
+ }
2276
+ else:
2277
+ # Unchanged field
2278
+ changes["unchanged"][key] = old_value
2279
+
2280
+ return [{
2281
+ "json": {
2282
+ "changes": changes,
2283
+ "summary": {
2284
+ "added_count": len(changes["added"]),
2285
+ "removed_count": len(changes["removed"]),
2286
+ "modified_count": len(changes["modified"]),
2287
+ "unchanged_count": len(changes["unchanged"]),
2288
+ "has_changes": len(changes["added"]) > 0 or len(changes["removed"]) > 0 or len(changes["modified"]) > 0
2289
+ }
2290
+ }
2291
+ }]
2292
+ ```
2293
+
2294
+ ### Key Techniques
2295
+
2296
+ - Set operations for key comparison
2297
+ - Dictionary .get() for safe access
2298
+ - Categorize changes by type
2299
+ - Create summary statistics
2300
+ - Return detailed comparison
2301
+
2302
+ ---
2303
+
2304
+ ## Pattern 5: CRM Data Transformation
2305
+
2306
+ **Use case**: Transform CRM data to standard format.
2307
+
2308
+ **Scenario**: Normalize data from different CRM systems.
2309
+
2310
+ ### Implementation
2311
+
2312
+ ```python
2313
+ from datetime import datetime
2314
+ import re
2315
+
2316
+ all_items = _input.all()
2317
+ normalized_contacts = []
2318
+
2319
+ for item in all_items:
2320
+ raw_contact = item["json"]
2321
+ source = raw_contact.get("source", "unknown")
2322
+
2323
+ # Normalize email
2324
+ email = raw_contact.get("email", "").lower().strip()
2325
+
2326
+ # Normalize phone (remove non-digits)
2327
+ phone_raw = raw_contact.get("phone", "")
2328
+ phone = re.sub(r'\D', '', phone_raw)
2329
+
2330
+ # Parse name
2331
+ if "full_name" in raw_contact:
2332
+ name_parts = raw_contact["full_name"].split(" ", 1)
2333
+ first_name = name_parts[0] if len(name_parts) > 0 else ""
2334
+ last_name = name_parts[1] if len(name_parts) > 1 else ""
2335
+ else:
2336
+ first_name = raw_contact.get("first_name", "")
2337
+ last_name = raw_contact.get("last_name", "")
2338
+
2339
+ # Normalize status
2340
+ status_raw = raw_contact.get("status", "").lower()
2341
+ status = "active" if status_raw in ["active", "enabled", "true", "1"] else "inactive"
2342
+
2343
+ # Create normalized contact
2344
+ normalized_contacts.append({
2345
+ "json": {
2346
+ "id": raw_contact.get("id", ""),
2347
+ "first_name": first_name.strip(),
2348
+ "last_name": last_name.strip(),
2349
+ "full_name": f"{first_name} {last_name}".strip(),
2350
+ "email": email,
2351
+ "phone": phone,
2352
+ "status": status,
2353
+ "source": source,
2354
+ "normalized_at": datetime.now().isoformat(),
2355
+ "original_data": raw_contact
2356
+ }
2357
+ })
2358
+
2359
+ return normalized_contacts
2360
+ ```
2361
+
2362
+ ### Key Techniques
2363
+
2364
+ - Multiple field name variations handling
2365
+ - String cleaning and normalization
2366
+ - Regex for phone number cleaning
2367
+ - Name parsing logic
2368
+ - Status normalization
2369
+ - Preserve original data
2370
+
2371
+ ---
2372
+
2373
+ ## Pattern 6: Release Notes Processing
2374
+
2375
+ **Use case**: Parse release notes and categorize changes.
2376
+
2377
+ **Scenario**: Extract features, fixes, and breaking changes from release notes.
2378
+
2379
+ ### Implementation
2380
+
2381
+ ```python
2382
+ import re
2383
+
2384
+ release_notes = _input.first()["json"]["body"].get("notes", "")
2385
+
2386
+ categories = {
2387
+ "features": [],
2388
+ "fixes": [],
2389
+ "breaking": [],
2390
+ "other": []
2391
+ }
2392
+
2393
+ # Split into lines
2394
+ lines = release_notes.split("\n")
2395
+
2396
+ for line in lines:
2397
+ line = line.strip()
2398
+
2399
+ # Skip empty lines and headers
2400
+ if not line or line.startswith("#"):
2401
+ continue
2402
+
2403
+ # Remove bullet points
2404
+ clean_line = re.sub(r'^[\*\-\+]\s*', '', line)
2405
+
2406
+ # Categorize
2407
+ if re.search(r'\b(feature|add|new)\b', clean_line, re.IGNORECASE):
2408
+ categories["features"].append(clean_line)
2409
+ elif re.search(r'\b(fix|bug|patch|resolve)\b', clean_line, re.IGNORECASE):
2410
+ categories["fixes"].append(clean_line)
2411
+ elif re.search(r'\b(breaking|deprecated|remove)\b', clean_line, re.IGNORECASE):
2412
+ categories["breaking"].append(clean_line)
2413
+ else:
2414
+ categories["other"].append(clean_line)
2415
+
2416
+ return [{
2417
+ "json": {
2418
+ "categories": categories,
2419
+ "summary": {
2420
+ "features": len(categories["features"]),
2421
+ "fixes": len(categories["fixes"]),
2422
+ "breaking": len(categories["breaking"]),
2423
+ "other": len(categories["other"]),
2424
+ "total": sum(len(v) for v in categories.values())
2425
+ }
2426
+ }
2427
+ }]
2428
+ ```
2429
+
2430
+ ### Key Techniques
2431
+
2432
+ - Line-by-line parsing
2433
+ - Pattern-based categorization
2434
+ - Bullet point removal
2435
+ - Skip headers and empty lines
2436
+ - Summary statistics
2437
+
2438
+ ---
2439
+
2440
+ ## Pattern 7: Array Transformation
2441
+
2442
+ **Use case**: Reshape arrays and extract specific fields.
2443
+
2444
+ **Scenario**: Transform user data array to extract specific fields.
2445
+
2446
+ ### Implementation
2447
+
2448
+ ```python
2449
+ all_items = _input.all()
2450
+
2451
+ # Extract and transform
2452
+ transformed = []
2453
+
2454
+ for item in all_items:
2455
+ user = item["json"]
2456
+
2457
+ # Extract nested fields
2458
+ profile = user.get("profile", {})
2459
+ settings = user.get("settings", {})
2460
+
2461
+ transformed.append({
2462
+ "json": {
2463
+ "user_id": user.get("id"),
2464
+ "email": user.get("email"),
2465
+ "name": profile.get("name", "Unknown"),
2466
+ "avatar": profile.get("avatar_url"),
2467
+ "bio": profile.get("bio", "")[:100], # Truncate to 100 chars
2468
+ "notifications_enabled": settings.get("notifications", True),
2469
+ "theme": settings.get("theme", "light"),
2470
+ "created_at": user.get("created_at"),
2471
+ "last_login": user.get("last_login_at")
2472
+ }
2473
+ })
2474
+
2475
+ return transformed
2476
+ ```
2477
+
2478
+ ### Key Techniques
2479
+
2480
+ - Field extraction from nested objects
2481
+ - Default values with .get()
2482
+ - String truncation
2483
+ - Flattening nested structures
2484
+
2485
+ ---
2486
+
2487
+ ## Pattern 8: Dictionary Lookup
2488
+
2489
+ **Use case**: Create lookup dictionary for fast data access.
2490
+
2491
+ **Scenario**: Look up user details by ID.
2492
+
2493
+ ### Implementation
2494
+
2495
+ ```python
2496
+ all_items = _input.all()
2497
+
2498
+ # Build lookup dictionary
2499
+ users_by_id = {}
2500
+
2501
+ for item in all_items:
2502
+ user = item["json"]
2503
+ user_id = user.get("id")
2504
+
2505
+ if user_id:
2506
+ users_by_id[user_id] = {
2507
+ "name": user.get("name"),
2508
+ "email": user.get("email"),
2509
+ "status": user.get("status")
2510
+ }
2511
+
2512
+ # Example: Look up specific users
2513
+ lookup_ids = [1, 3, 5]
2514
+ looked_up = []
2515
+
2516
+ for user_id in lookup_ids:
2517
+ if user_id in users_by_id:
2518
+ looked_up.append({
2519
+ "json": {
2520
+ "id": user_id,
2521
+ **users_by_id[user_id],
2522
+ "found": True
2523
+ }
2524
+ })
2525
+ else:
2526
+ looked_up.append({
2527
+ "json": {
2528
+ "id": user_id,
2529
+ "found": False
2530
+ }
2531
+ })
2532
+
2533
+ return looked_up
2534
+ ```
2535
+
2536
+ ### Key Techniques
2537
+
2538
+ - Dictionary comprehension alternative
2539
+ - O(1) lookup time
2540
+ - Handle missing keys gracefully
2541
+ - Preserve lookup order
2542
+
2543
+ ---
2544
+
2545
+ ## Pattern 9: Top N Filtering
2546
+
2547
+ **Use case**: Get top items by score or value.
2548
+
2549
+ **Scenario**: Get top 10 products by sales.
2550
+
2551
+ ### Implementation
2552
+
2553
+ ```python
2554
+ all_items = _input.all()
2555
+
2556
+ # Extract products with sales
2557
+ products = []
2558
+
2559
+ for item in all_items:
2560
+ product = item["json"]
2561
+ products.append({
2562
+ "id": product.get("id"),
2563
+ "name": product.get("name"),
2564
+ "sales": product.get("sales", 0),
2565
+ "revenue": product.get("revenue", 0.0),
2566
+ "category": product.get("category")
2567
+ })
2568
+
2569
+ # Sort by sales descending
2570
+ products.sort(key=lambda p: p["sales"], reverse=True)
2571
+
2572
+ # Get top 10
2573
+ top_10 = products[:10]
2574
+
2575
+ return [
2576
+ {
2577
+ "json": {
2578
+ **product,
2579
+ "rank": index + 1
2580
+ }
2581
+ }
2582
+ for index, product in enumerate(top_10)
2583
+ ]
2584
+ ```
2585
+
2586
+ ### Key Techniques
2587
+
2588
+ - List sorting with custom key
2589
+ - Slicing for top N
2590
+ - Add ranking information
2591
+ - Enumerate for index
2592
+
2593
+ ---
2594
+
2595
+ ## Pattern 10: String Aggregation
2596
+
2597
+ **Use case**: Aggregate strings with formatting.
2598
+
2599
+ **Scenario**: Create summary text from multiple items.
2600
+
2601
+ ### Implementation
2602
+
2603
+ ```python
2604
+ all_items = _input.all()
2605
+
2606
+ # Collect messages
2607
+ messages = []
2608
+
2609
+ for item in all_items:
2610
+ data = item["json"]
2611
+
2612
+ user = data.get("user", "Unknown")
2613
+ message = data.get("message", "")
2614
+ timestamp = data.get("timestamp", "")
2615
+
2616
+ # Format each message
2617
+ formatted = f"[{timestamp}] {user}: {message}"
2618
+ messages.append(formatted)
2619
+
2620
+ # Join with newlines
2621
+ summary = "\n".join(messages)
2622
+
2623
+ # Create statistics
2624
+ total_length = sum(len(msg) for msg in messages)
2625
+ average_length = total_length / len(messages) if messages else 0
2626
+
2627
+ return [{
2628
+ "json": {
2629
+ "summary": summary,
2630
+ "message_count": len(messages),
2631
+ "total_characters": total_length,
2632
+ "average_length": round(average_length, 2)
2633
+ }
2634
+ }]
2635
+ ```
2636
+
2637
+ ### Key Techniques
2638
+
2639
+ - String formatting with f-strings
2640
+ - Join lists with separator
2641
+ - Calculate string statistics
2642
+ - Handle empty lists
2643
+
2644
+ ---
2645
+
2646
+ ## Pattern Comparison: Python vs JavaScript
2647
+
2648
+ ### Data Access
2649
+
2650
+ ```python
2651
+ # Python
2652
+ all_items = _input.all()
2653
+ first_item = _input.first()
2654
+ current = _input.item
2655
+ webhook_data = _json["body"]
2656
+
2657
+ # JavaScript
2658
+ const allItems = $input.all();
2659
+ const firstItem = $input.first();
2660
+ const current = $input.item;
2661
+ const webhookData = $json.body;
2662
+ ```
2663
+
2664
+ ### Dictionary/Object Access
2665
+
2666
+ ```python
2667
+ # Python - Dictionary key access
2668
+ name = user["name"] # May raise KeyError
2669
+ name = user.get("name", "?") # Safe with default
2670
+
2671
+ # JavaScript - Object property access
2672
+ const name = user.name; // May be undefined
2673
+ const name = user.name || "?"; // Safe with default
2674
+ ```
2675
+
2676
+ ### Array Operations
2677
+
2678
+ ```python
2679
+ # Python - List comprehension
2680
+ filtered = [item for item in items if item["active"]]
2681
+
2682
+ # JavaScript - Array methods
2683
+ const filtered = items.filter(item => item.active);
2684
+ ```
2685
+
2686
+ ### Sorting
2687
+
2688
+ ```python
2689
+ # Python
2690
+ items.sort(key=lambda x: x["score"], reverse=True)
2691
+
2692
+ # JavaScript
2693
+ items.sort((a, b) => b.score - a.score);
2694
+ ```
2695
+
2696
+ ---
2697
+
2698
+ ## When to Use Each Pattern
2699
+
2700
+ | Pattern | When to Use |
2701
+ | ------------------------ | ---------------------------------------------- |
2702
+ | Multi-Source Aggregation | Combining data from different nodes/sources |
2703
+ | Regex Filtering | Text pattern matching, validation, extraction |
2704
+ | Markdown Parsing | Processing formatted text into structured data |
2705
+ | JSON Comparison | Detecting changes between objects |
2706
+ | CRM Transformation | Normalizing data from different systems |
2707
+ | Release Notes | Categorizing text by keywords |
2708
+ | Array Transformation | Reshaping data, extracting fields |
2709
+ | Dictionary Lookup | Fast ID-based lookups |
2710
+ | Top N Filtering | Getting best/worst items by criteria |
2711
+ | String Aggregation | Creating formatted text summaries |
2712
+
2713
+ ---
2714
+
2715
+ # Error Patterns - Python Code Node
2716
+
2717
+ Common Python Code node errors and how to fix them.
2718
+
2719
+ ---
2720
+
2721
+ ## Error Overview
2722
+
2723
+ **Top 5 Python Code Node Errors**:
2724
+
2725
+ 1. **ModuleNotFoundError** - Trying to import external libraries (Python-specific)
2726
+ 2. **Empty Code / Missing Return** - No code or return statement
2727
+ 3. **KeyError** - Dictionary access without .get()
2728
+ 4. **IndexError** - List access without bounds checking
2729
+ 5. **Incorrect Return Format** - Wrong data structure returned
2730
+
2731
+ These 5 errors cover the majority of Python Code node failures.
2732
+
2733
+ ---
2734
+
2735
+ ## Error #1: ModuleNotFoundError (MOST CRITICAL)
2736
+
2737
+ **Frequency**: Very common in Python Code nodes
2738
+
2739
+ **What it is**: Attempting to import external libraries that aren't available.
2740
+
2741
+ ### The Problem
2742
+
2743
+ ```python
2744
+ # WRONG: External libraries not available
2745
+ import requests # ModuleNotFoundError: No module named 'requests'
2746
+ import pandas # ModuleNotFoundError: No module named 'pandas'
2747
+ import numpy # ModuleNotFoundError: No module named 'numpy'
2748
+ import bs4 # ModuleNotFoundError: No module named 'bs4'
2749
+ import pymongo # ModuleNotFoundError: No module named 'pymongo'
2750
+ import psycopg2 # ModuleNotFoundError: No module named 'psycopg2'
2751
+
2752
+ # This code will FAIL - these libraries are not installed!
2753
+ response = requests.get("https://api.example.com/data")
2754
+ ```
2755
+
2756
+ ### The Solution
2757
+
2758
+ **Option 1: Use JavaScript Instead** (Recommended for 95% of cases)
2759
+
2760
+ ```javascript
2761
+ // JavaScript Code node with $helpers.httpRequest()
2762
+ const response = await $helpers.httpRequest({
2763
+ method: "GET",
2764
+ url: "https://api.example.com/data",
2765
+ });
2766
+
2767
+ return [{ json: response }];
2768
+ ```
2769
+
2770
+ **Option 2: Use n8n HTTP Request Node**
2771
+
2772
+ ```python
2773
+ # Add HTTP Request node BEFORE Python Code node
2774
+ # Access the response in Python Code node
2775
+
2776
+ response = _input.first()["json"]
2777
+
2778
+ return [{
2779
+ "json": {
2780
+ "status": response.get("status"),
2781
+ "data": response.get("body"),
2782
+ "processed": True
2783
+ }
2784
+ }]
2785
+ ```
2786
+
2787
+ **Option 3: Use Standard Library Only**
2788
+
2789
+ ```python
2790
+ # Use urllib from standard library (limited functionality)
2791
+ from urllib.request import urlopen
2792
+ from urllib.parse import urlencode
2793
+ import json
2794
+
2795
+ # Simple GET request (no headers, no auth)
2796
+ url = "https://api.example.com/data"
2797
+ with urlopen(url) as response:
2798
+ data = json.loads(response.read())
2799
+
2800
+ return [{"json": data}]
2801
+ ```
2802
+
2803
+ ### Common Library Replacements
2804
+
2805
+ | Need | External Library | Alternative |
2806
+ | ---------------- | --------------------- | ----------------------------------- |
2807
+ | HTTP requests | `requests` | Use HTTP Request node or JavaScript |
2808
+ | Data analysis | `pandas` | Use Python list comprehensions |
2809
+ | Database | `psycopg2`, `pymongo` | Use n8n database nodes |
2810
+ | Web scraping | `beautifulsoup4` | Use HTML Extract node |
2811
+ | Excel | `openpyxl` | Use Spreadsheet File node |
2812
+ | Image processing | `pillow` | Use external API or node |
2813
+
2814
+ ### Available Standard Library Modules
2815
+
2816
+ ```python
2817
+ # THESE WORK - Standard library only
2818
+ import json # JSON parsing
2819
+ import datetime # Date/time operations
2820
+ import re # Regular expressions
2821
+ import base64 # Base64 encoding
2822
+ import hashlib # Hashing (MD5, SHA256)
2823
+ import urllib.parse # URL parsing and encoding
2824
+ import math # Math functions
2825
+ import random # Random numbers
2826
+ import statistics # Statistical functions
2827
+ import collections # defaultdict, Counter, etc.
2828
+ ```
2829
+
2830
+ ---
2831
+
2832
+ ## Error #2: Empty Code / Missing Return
2833
+
2834
+ **Frequency**: Common across all Code nodes
2835
+
2836
+ **What it is**: Code node has no code or no return statement.
2837
+
2838
+ ### The Problem
2839
+
2840
+ ```python
2841
+ # WRONG: Empty code
2842
+ # (nothing here)
2843
+
2844
+ # WRONG: Code but no return
2845
+ items = _input.all()
2846
+ processed = [item for item in items if item["json"].get("active")]
2847
+ # Forgot to return!
2848
+
2849
+ # WRONG: Return in wrong scope
2850
+ if _input.all():
2851
+ return [{"json": {"result": "success"}}]
2852
+ # Return is inside if block - may not execute!
2853
+ ```
2854
+
2855
+ ### The Solution
2856
+
2857
+ ```python
2858
+ # CORRECT: Always return
2859
+ all_items = _input.all()
2860
+
2861
+ if not all_items:
2862
+ # Return empty array or error
2863
+ return [{"json": {"error": "No items"}}]
2864
+
2865
+ # Process items
2866
+ processed = [item for item in all_items if item["json"].get("active")]
2867
+
2868
+ # Always return at the end
2869
+ return processed if processed else [{"json": {"message": "No active items"}}]
2870
+ ```
2871
+
2872
+ ### Best Practice
2873
+
2874
+ ```python
2875
+ # GOOD: Return at end of function (unconditional)
2876
+ def process_items():
2877
+ items = _input.all()
2878
+
2879
+ if not items:
2880
+ return [{"json": {"error": "Empty input"}}]
2881
+
2882
+ # Process
2883
+ result = []
2884
+ for item in items:
2885
+ result.append({"json": item["json"]})
2886
+
2887
+ return result
2888
+
2889
+ # Call function and return result
2890
+ return process_items()
2891
+ ```
2892
+
2893
+ ---
2894
+
2895
+ ## Error #3: KeyError
2896
+
2897
+ **Frequency**: Very common in Python Code nodes
2898
+
2899
+ **What it is**: Accessing dictionary key that doesn't exist.
2900
+
2901
+ ### The Problem
2902
+
2903
+ ```python
2904
+ # WRONG: Direct key access
2905
+ item = _input.first()["json"]
2906
+
2907
+ name = item["name"] # KeyError if "name" doesn't exist!
2908
+ email = item["email"] # KeyError if "email" doesn't exist!
2909
+ age = item["age"] # KeyError if "age" doesn't exist!
2910
+
2911
+ return [{
2912
+ "json": {
2913
+ "name": name,
2914
+ "email": email,
2915
+ "age": age
2916
+ }
2917
+ }]
2918
+ ```
2919
+
2920
+ ### Error Message
2921
+
2922
+ ```
2923
+ KeyError: 'name'
2924
+ ```
2925
+
2926
+ ### The Solution
2927
+
2928
+ ```python
2929
+ # CORRECT: Use .get() with defaults
2930
+ item = _input.first()["json"]
2931
+
2932
+ name = item.get("name", "Unknown")
2933
+ email = item.get("email", "no-email@example.com")
2934
+ age = item.get("age", 0)
2935
+
2936
+ return [{
2937
+ "json": {
2938
+ "name": name,
2939
+ "email": email,
2940
+ "age": age
2941
+ }
2942
+ }]
2943
+ ```
2944
+
2945
+ ### Nested Dictionary Access
2946
+
2947
+ ```python
2948
+ # WRONG: Nested key access
2949
+ webhook = _input.first()["json"]
2950
+ name = webhook["body"]["user"]["name"] # Multiple KeyErrors possible!
2951
+
2952
+ # CORRECT: Safe nested access
2953
+ webhook = _input.first()["json"]
2954
+ body = webhook.get("body", {})
2955
+ user = body.get("user", {})
2956
+ name = user.get("name", "Unknown")
2957
+
2958
+ # ALSO CORRECT: Chained .get()
2959
+ name = (
2960
+ webhook
2961
+ .get("body", {})
2962
+ .get("user", {})
2963
+ .get("name", "Unknown")
2964
+ )
2965
+
2966
+ return [{"json": {"name": name}}]
2967
+ ```
2968
+
2969
+ ### Webhook Body Access (Critical!)
2970
+
2971
+ ```python
2972
+ # WRONG: Forgetting webhook data is under "body"
2973
+ webhook = _input.first()["json"]
2974
+ name = webhook["name"] # KeyError!
2975
+ email = webhook["email"] # KeyError!
2976
+
2977
+ # CORRECT: Access via ["body"]
2978
+ webhook = _input.first()["json"]
2979
+ body = webhook.get("body", {})
2980
+ name = body.get("name", "Unknown")
2981
+ email = body.get("email", "no-email")
2982
+
2983
+ return [{
2984
+ "json": {
2985
+ "name": name,
2986
+ "email": email
2987
+ }
2988
+ }]
2989
+ ```
2990
+
2991
+ ---
2992
+
2993
+ ## Error #4: IndexError
2994
+
2995
+ **Frequency**: Common when processing arrays/lists
2996
+
2997
+ **What it is**: Accessing list index that doesn't exist.
2998
+
2999
+ ### The Problem
3000
+
3001
+ ```python
3002
+ # WRONG: Assuming items exist
3003
+ all_items = _input.all()
3004
+ first_item = all_items[0] # IndexError if list is empty!
3005
+ second_item = all_items[1] # IndexError if only 1 item!
3006
+
3007
+ return [{
3008
+ "json": {
3009
+ "first": first_item["json"],
3010
+ "second": second_item["json"]
3011
+ }
3012
+ }]
3013
+ ```
3014
+
3015
+ ### Error Message
3016
+
3017
+ ```
3018
+ IndexError: list index out of range
3019
+ ```
3020
+
3021
+ ### The Solution
3022
+
3023
+ ```python
3024
+ # CORRECT: Check length first
3025
+ all_items = _input.all()
3026
+
3027
+ if len(all_items) >= 2:
3028
+ first_item = all_items[0]["json"]
3029
+ second_item = all_items[1]["json"]
3030
+
3031
+ return [{
3032
+ "json": {
3033
+ "first": first_item,
3034
+ "second": second_item
3035
+ }
3036
+ }]
3037
+ else:
3038
+ return [{
3039
+ "json": {
3040
+ "error": f"Expected 2+ items, got {len(all_items)}"
3041
+ }
3042
+ }]
3043
+ ```
3044
+
3045
+ ### Safe First Item Access
3046
+
3047
+ ```python
3048
+ # CORRECT: Use _input.first() instead of [0]
3049
+ # This is safer than manual indexing
3050
+ first_item = _input.first()["json"]
3051
+
3052
+ return [{"json": first_item}]
3053
+
3054
+ # ALSO CORRECT: Check before accessing
3055
+ all_items = _input.all()
3056
+ if all_items:
3057
+ first_item = all_items[0]["json"]
3058
+ else:
3059
+ first_item = {}
3060
+
3061
+ return [{"json": first_item}]
3062
+ ```
3063
+
3064
+ ### Slice Instead of Index
3065
+
3066
+ ```python
3067
+ # CORRECT: Use slicing (never raises IndexError)
3068
+ all_items = _input.all()
3069
+
3070
+ # Get first 5 items (won't fail if fewer than 5)
3071
+ first_five = all_items[:5]
3072
+
3073
+ # Get items after first (won't fail if empty)
3074
+ rest = all_items[1:]
3075
+
3076
+ return [{"json": item["json"]} for item in first_five]
3077
+ ```
3078
+
3079
+ ---
3080
+
3081
+ ## Error #5: Incorrect Return Format
3082
+
3083
+ **Frequency**: Common for new users
3084
+
3085
+ **What it is**: Returning data in wrong format (n8n expects array of objects with "json" key).
3086
+
3087
+ ### The Problem
3088
+
3089
+ ```python
3090
+ # WRONG: Returning plain dictionary
3091
+ return {"name": "Alice", "age": 30}
3092
+
3093
+ # WRONG: Returning array without "json" wrapper
3094
+ return [{"name": "Alice"}, {"name": "Bob"}]
3095
+
3096
+ # WRONG: Returning None
3097
+ return None
3098
+
3099
+ # WRONG: Returning string
3100
+ return "success"
3101
+
3102
+ # WRONG: Returning single item (not array)
3103
+ return {"json": {"name": "Alice"}}
3104
+ ```
3105
+
3106
+ ### The Solution
3107
+
3108
+ ```python
3109
+ # CORRECT: Array of objects with "json" key
3110
+ return [{"json": {"name": "Alice", "age": 30}}]
3111
+
3112
+ # CORRECT: Multiple items
3113
+ return [
3114
+ {"json": {"name": "Alice"}},
3115
+ {"json": {"name": "Bob"}}
3116
+ ]
3117
+
3118
+ # CORRECT: Transform items
3119
+ all_items = _input.all()
3120
+ return [
3121
+ {"json": item["json"]}
3122
+ for item in all_items
3123
+ ]
3124
+
3125
+ # CORRECT: Empty array (valid)
3126
+ return []
3127
+
3128
+ # CORRECT: Single item still needs array wrapper
3129
+ return [{"json": {"result": "success"}}]
3130
+ ```
3131
+
3132
+ ### Common Scenarios
3133
+
3134
+ **Scenario 1: Aggregation (Return Single Result)**
3135
+
3136
+ ```python
3137
+ # Calculate total
3138
+ all_items = _input.all()
3139
+ total = sum(item["json"].get("amount", 0) for item in all_items)
3140
+
3141
+ # CORRECT: Wrap in array with "json"
3142
+ return [{
3143
+ "json": {
3144
+ "total": total,
3145
+ "count": len(all_items)
3146
+ }
3147
+ }]
3148
+ ```
3149
+
3150
+ **Scenario 2: Filtering (Return Multiple Results)**
3151
+
3152
+ ```python
3153
+ # Filter active items
3154
+ all_items = _input.all()
3155
+ active = [item for item in all_items if item["json"].get("active")]
3156
+
3157
+ # CORRECT: Already in correct format
3158
+ return active
3159
+
3160
+ # ALSO CORRECT: If transforming
3161
+ return [
3162
+ {"json": {**item["json"], "filtered": True}}
3163
+ for item in active
3164
+ ]
3165
+ ```
3166
+
3167
+ **Scenario 3: No Results**
3168
+
3169
+ ```python
3170
+ # CORRECT: Return empty array
3171
+ return []
3172
+
3173
+ # ALSO CORRECT: Return error message
3174
+ return [{"json": {"error": "No results found"}}]
3175
+ ```
3176
+
3177
+ ---
3178
+
3179
+ ## Bonus Error: AttributeError
3180
+
3181
+ **What it is**: Using \_input.item in wrong mode.
3182
+
3183
+ ### The Problem
3184
+
3185
+ ```python
3186
+ # WRONG: Using _input.item in "All Items" mode
3187
+ current = _input.item # None in "All Items" mode
3188
+ data = current["json"] # AttributeError: 'NoneType' object has no attribute '__getitem__'
3189
+ ```
3190
+
3191
+ ### The Solution
3192
+
3193
+ ```python
3194
+ # CORRECT: Check mode or use appropriate method
3195
+ # In "All Items" mode, use:
3196
+ all_items = _input.all()
3197
+
3198
+ # In "Each Item" mode, use:
3199
+ current_item = _input.item
3200
+
3201
+ # SAFE: Check if item exists
3202
+ current = _input.item
3203
+ if current:
3204
+ data = current["json"]
3205
+ return [{"json": data}]
3206
+ else:
3207
+ # Running in "All Items" mode
3208
+ return _input.all()
3209
+ ```
3210
+
3211
+ ---
3212
+
3213
+ ## Error Prevention Checklist
3214
+
3215
+ Before running your Python Code node, verify:
3216
+
3217
+ - [ ] **No external imports**: Only standard library (json, datetime, re, etc.)
3218
+ - [ ] **Code returns data**: Every code path ends with `return`
3219
+ - [ ] **Correct format**: Returns `[{"json": {...}}]` (array with "json" key)
3220
+ - [ ] **Safe dictionary access**: Uses `.get()` instead of `[]` for dictionaries
3221
+ - [ ] **Safe list access**: Checks length before indexing or uses slicing
3222
+ - [ ] **Webhook body access**: Accesses webhook data via `_json["body"]`
3223
+ - [ ] **No None returns**: Returns empty array `[]` instead of `None`
3224
+ - [ ] **Mode awareness**: Uses `_input.all()`, `_input.first()`, or `_input.item` appropriately
3225
+
3226
+ ---
3227
+
3228
+ ## Quick Fix Reference
3229
+
3230
+ | Error | Quick Fix |
3231
+ | ------------------------------------- | ------------------------------------------------------ |
3232
+ | `ModuleNotFoundError` | Use JavaScript or HTTP Request node instead |
3233
+ | `KeyError: 'field'` | Change `data["field"]` to `data.get("field", default)` |
3234
+ | `IndexError: list index out of range` | Check `if len(items) > 0:` before `items[0]` |
3235
+ | Empty output | Add `return [{"json": {...}}]` at end |
3236
+ | `AttributeError: 'NoneType'` | Check mode setting or verify `_input.item` exists |
3237
+ | Wrong format error | Wrap result: `return [{"json": result}]` |
3238
+ | Webhook KeyError | Access via `_json.get("body", {})` |
3239
+
3240
+ ---
3241
+
3242
+ ## Testing Your Code
3243
+
3244
+ ### Test Pattern 1: Handle Empty Input
3245
+
3246
+ ```python
3247
+ # Always test with empty input
3248
+ all_items = _input.all()
3249
+
3250
+ if not all_items:
3251
+ return [{"json": {"message": "No items to process"}}]
3252
+
3253
+ # Continue with processing
3254
+ # ...
3255
+ ```
3256
+
3257
+ ### Test Pattern 2: Test with Missing Fields
3258
+
3259
+ ```python
3260
+ # Use .get() with defaults
3261
+ item = _input.first()["json"]
3262
+
3263
+ # These won't fail even if fields missing
3264
+ name = item.get("name", "Unknown")
3265
+ email = item.get("email", "no-email")
3266
+ age = item.get("age", 0)
3267
+
3268
+ return [{"json": {"name": name, "email": email, "age": age}}]
3269
+ ```
3270
+
3271
+ ### Test Pattern 3: Test Both Modes
3272
+
3273
+ ```python
3274
+ # Code that works in both modes
3275
+ try:
3276
+ # Try "Each Item" mode first
3277
+ current = _input.item
3278
+ if current:
3279
+ return [{"json": current["json"]}]
3280
+ except:
3281
+ pass
3282
+
3283
+ # Fall back to "All Items" mode
3284
+ all_items = _input.all()
3285
+ return all_items if all_items else [{"json": {"message": "No data"}}]
3286
+ ```
3287
+
3288
+ ---
3289
+
3290
+ ## n8n Documentation
3291
+
3292
+ - Code Node Guide: https://docs.n8n.io/code/code-node/
3293
+ - Python in n8n: https://docs.n8n.io/code/builtin/python-modules/