opencode-skills-collection 1.0.185 → 1.0.187

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 (71) hide show
  1. package/bundled-skills/.antigravity-install-manifest.json +5 -1
  2. package/bundled-skills/3d-web-experience/SKILL.md +152 -37
  3. package/bundled-skills/agent-evaluation/SKILL.md +1088 -26
  4. package/bundled-skills/agent-memory-systems/SKILL.md +1037 -25
  5. package/bundled-skills/agent-tool-builder/SKILL.md +668 -16
  6. package/bundled-skills/ai-agents-architect/SKILL.md +271 -31
  7. package/bundled-skills/ai-product/SKILL.md +716 -26
  8. package/bundled-skills/ai-wrapper-product/SKILL.md +450 -44
  9. package/bundled-skills/algolia-search/SKILL.md +867 -15
  10. package/bundled-skills/autonomous-agents/SKILL.md +1033 -26
  11. package/bundled-skills/aws-serverless/SKILL.md +1046 -35
  12. package/bundled-skills/azure-functions/SKILL.md +1318 -19
  13. package/bundled-skills/browser-automation/SKILL.md +1065 -28
  14. package/bundled-skills/browser-extension-builder/SKILL.md +159 -32
  15. package/bundled-skills/bullmq-specialist/SKILL.md +347 -16
  16. package/bundled-skills/clerk-auth/SKILL.md +796 -15
  17. package/bundled-skills/computer-use-agents/SKILL.md +1870 -28
  18. package/bundled-skills/context-window-management/SKILL.md +271 -18
  19. package/bundled-skills/conversation-memory/SKILL.md +453 -24
  20. package/bundled-skills/crewai/SKILL.md +252 -46
  21. package/bundled-skills/discord-bot-architect/SKILL.md +1207 -34
  22. package/bundled-skills/docs/integrations/jetski-cortex.md +3 -3
  23. package/bundled-skills/docs/integrations/jetski-gemini-loader/README.md +1 -1
  24. package/bundled-skills/docs/maintainers/repo-growth-seo.md +3 -3
  25. package/bundled-skills/docs/maintainers/skills-update-guide.md +1 -1
  26. package/bundled-skills/docs/users/bundles.md +1 -1
  27. package/bundled-skills/docs/users/claude-code-skills.md +1 -1
  28. package/bundled-skills/docs/users/gemini-cli-skills.md +1 -1
  29. package/bundled-skills/docs/users/getting-started.md +1 -1
  30. package/bundled-skills/docs/users/kiro-integration.md +1 -1
  31. package/bundled-skills/docs/users/usage.md +4 -4
  32. package/bundled-skills/docs/users/visual-guide.md +4 -4
  33. package/bundled-skills/email-systems/SKILL.md +646 -26
  34. package/bundled-skills/faf-expert/SKILL.md +221 -0
  35. package/bundled-skills/faf-wizard/SKILL.md +252 -0
  36. package/bundled-skills/file-uploads/SKILL.md +212 -11
  37. package/bundled-skills/firebase/SKILL.md +646 -16
  38. package/bundled-skills/gcp-cloud-run/SKILL.md +1117 -32
  39. package/bundled-skills/graphql/SKILL.md +1026 -27
  40. package/bundled-skills/hubspot-integration/SKILL.md +804 -19
  41. package/bundled-skills/idea-darwin/SKILL.md +120 -0
  42. package/bundled-skills/inngest/SKILL.md +431 -16
  43. package/bundled-skills/interactive-portfolio/SKILL.md +342 -44
  44. package/bundled-skills/langfuse/SKILL.md +296 -41
  45. package/bundled-skills/langgraph/SKILL.md +259 -50
  46. package/bundled-skills/micro-saas-launcher/SKILL.md +343 -44
  47. package/bundled-skills/neon-postgres/SKILL.md +572 -15
  48. package/bundled-skills/nextjs-supabase-auth/SKILL.md +269 -21
  49. package/bundled-skills/notion-template-business/SKILL.md +371 -44
  50. package/bundled-skills/personal-tool-builder/SKILL.md +537 -44
  51. package/bundled-skills/plaid-fintech/SKILL.md +825 -19
  52. package/bundled-skills/prompt-caching/SKILL.md +438 -25
  53. package/bundled-skills/rag-engineer/SKILL.md +271 -29
  54. package/bundled-skills/salesforce-development/SKILL.md +912 -19
  55. package/bundled-skills/satori/SKILL.md +54 -0
  56. package/bundled-skills/scroll-experience/SKILL.md +381 -44
  57. package/bundled-skills/segment-cdp/SKILL.md +817 -19
  58. package/bundled-skills/shopify-apps/SKILL.md +1475 -19
  59. package/bundled-skills/slack-bot-builder/SKILL.md +1162 -28
  60. package/bundled-skills/telegram-bot-builder/SKILL.md +152 -37
  61. package/bundled-skills/telegram-mini-app/SKILL.md +445 -44
  62. package/bundled-skills/trigger-dev/SKILL.md +916 -27
  63. package/bundled-skills/twilio-communications/SKILL.md +1310 -28
  64. package/bundled-skills/upstash-qstash/SKILL.md +898 -27
  65. package/bundled-skills/vercel-deployment/SKILL.md +637 -39
  66. package/bundled-skills/viral-generator-builder/SKILL.md +132 -37
  67. package/bundled-skills/voice-agents/SKILL.md +937 -27
  68. package/bundled-skills/voice-ai-development/SKILL.md +375 -46
  69. package/bundled-skills/workflow-automation/SKILL.md +982 -29
  70. package/bundled-skills/zapier-make-patterns/SKILL.md +772 -27
  71. package/package.json +1 -1
@@ -1,24 +1,37 @@
1
1
  ---
2
2
  name: workflow-automation
3
- description: "You are a workflow automation architect who has seen both the promise and the pain of these platforms. You've migrated teams from brittle cron jobs to durable execution and watched their on-call burden drop by 80%."
3
+ description: Workflow automation is the infrastructure that makes AI agents
4
+ reliable. Without durable execution, a network hiccup during a 10-step payment
5
+ flow means lost money and angry customers. With it, workflows resume exactly
6
+ where they left off.
4
7
  risk: critical
5
- source: "vibeship-spawner-skills (Apache 2.0)"
6
- date_added: "2026-02-27"
8
+ source: vibeship-spawner-skills (Apache 2.0)
9
+ date_added: 2026-02-27
7
10
  ---
8
11
 
9
12
  # Workflow Automation
10
13
 
11
- You are a workflow automation architect who has seen both the promise and
12
- the pain of these platforms. You've migrated teams from brittle cron jobs
13
- to durable execution and watched their on-call burden drop by 80%.
14
+ Workflow automation is the infrastructure that makes AI agents reliable.
15
+ Without durable execution, a network hiccup during a 10-step payment
16
+ flow means lost money and angry customers. With it, workflows resume
17
+ exactly where they left off.
14
18
 
15
- Your core insight: Different platforms make different tradeoffs. n8n is
16
- accessible but sacrifices performance. Temporal is correct but complex.
17
- Inngest balances developer experience with reliability. DBOS uses your
18
- existing PostgreSQL for durable execution with minimal infrastructure
19
- overhead. There's no "best" - only "best for your situation."
19
+ This skill covers the platforms (n8n, Temporal, Inngest) and patterns
20
+ (sequential, parallel, orchestrator-worker) that turn brittle scripts
21
+ into production-grade automation.
20
22
 
21
- You push for durable execution
23
+ Key insight: The platforms make different tradeoffs. n8n optimizes for
24
+ accessibility, Temporal for correctness, Inngest for developer experience.
25
+ Pick based on your actual needs, not hype.
26
+
27
+ ## Principles
28
+
29
+ - Durable execution is non-negotiable for money or state-critical workflows
30
+ - Events are the universal language of workflow triggers
31
+ - Steps are checkpoints - each should be independently retryable
32
+ - Start simple, add complexity only when reliability demands it
33
+ - Observability isn't optional - you need to see where workflows fail
34
+ - Workflows and agents co-evolve - design for both
22
35
 
23
36
  ## Capabilities
24
37
 
@@ -31,44 +44,984 @@ You push for durable execution
31
44
  - background-jobs
32
45
  - scheduled-tasks
33
46
 
47
+ ## Scope
48
+
49
+ - multi-agent-coordination → multi-agent-orchestration
50
+ - ci-cd-pipelines → devops
51
+ - data-pipelines → data-engineer
52
+ - api-design → api-designer
53
+
54
+ ## Tooling
55
+
56
+ ### Platforms
57
+
58
+ - n8n - When: Low-code automation, quick prototyping, non-technical users Note: Self-hostable, 400+ integrations, great for visual workflows
59
+ - Temporal - When: Mission-critical workflows, financial transactions, microservices Note: Strongest durability guarantees, steeper learning curve
60
+ - Inngest - When: Event-driven serverless, TypeScript codebases, AI workflows Note: Best developer experience, works with any hosting
61
+ - AWS Step Functions - When: AWS-native stacks, existing Lambda functions Note: Tight AWS integration, JSON-based workflow definition
62
+ - Azure Durable Functions - When: Azure stacks, .NET or TypeScript Note: Good AI agent support, checkpoint and replay
63
+
34
64
  ## Patterns
35
65
 
36
66
  ### Sequential Workflow Pattern
37
67
 
38
68
  Steps execute in order, each output becomes next input
39
69
 
70
+ **When to use**: Content pipelines, data processing, ordered operations
71
+
72
+ # SEQUENTIAL WORKFLOW:
73
+
74
+ """
75
+ Step 1 → Step 2 → Step 3 → Output
76
+ ↓ ↓ ↓
77
+ (checkpoint at each step)
78
+ """
79
+
80
+ ## Inngest Example (TypeScript)
81
+ """
82
+ import { inngest } from "./client";
83
+
84
+ export const processOrder = inngest.createFunction(
85
+ { id: "process-order" },
86
+ { event: "order/created" },
87
+ async ({ event, step }) => {
88
+ // Step 1: Validate order
89
+ const validated = await step.run("validate-order", async () => {
90
+ return validateOrder(event.data.order);
91
+ });
92
+
93
+ // Step 2: Process payment (durable - survives crashes)
94
+ const payment = await step.run("process-payment", async () => {
95
+ return chargeCard(validated.paymentMethod, validated.total);
96
+ });
97
+
98
+ // Step 3: Create shipment
99
+ const shipment = await step.run("create-shipment", async () => {
100
+ return createShipment(validated.items, validated.address);
101
+ });
102
+
103
+ // Step 4: Send confirmation
104
+ await step.run("send-confirmation", async () => {
105
+ return sendEmail(validated.email, { payment, shipment });
106
+ });
107
+
108
+ return { success: true, orderId: event.data.orderId };
109
+ }
110
+ );
111
+ """
112
+
113
+ ## Temporal Example (TypeScript)
114
+ """
115
+ import { proxyActivities } from '@temporalio/workflow';
116
+ import type * as activities from './activities';
117
+
118
+ const { validateOrder, chargeCard, createShipment, sendEmail } =
119
+ proxyActivities<typeof activities>({
120
+ startToCloseTimeout: '30 seconds',
121
+ retry: {
122
+ maximumAttempts: 3,
123
+ backoffCoefficient: 2,
124
+ }
125
+ });
126
+
127
+ export async function processOrderWorkflow(order: Order): Promise<void> {
128
+ const validated = await validateOrder(order);
129
+ const payment = await chargeCard(validated.paymentMethod, validated.total);
130
+ const shipment = await createShipment(validated.items, validated.address);
131
+ await sendEmail(validated.email, { payment, shipment });
132
+ }
133
+ """
134
+
135
+ ## n8n Pattern
136
+ """
137
+ [Webhook: order.created]
138
+
139
+ [HTTP Request: Validate Order]
140
+
141
+ [HTTP Request: Process Payment]
142
+
143
+ [HTTP Request: Create Shipment]
144
+
145
+ [Send Email: Confirmation]
146
+
147
+ Configure each node with retry on failure.
148
+ Use Error Trigger for dead letter handling.
149
+ """
150
+
40
151
  ### Parallel Workflow Pattern
41
152
 
42
153
  Independent steps run simultaneously, aggregate results
43
154
 
155
+ **When to use**: Multiple independent analyses, data from multiple sources
156
+
157
+ # PARALLEL WORKFLOW:
158
+
159
+ """
160
+ ┌→ Step A ─┐
161
+ Input ──┼→ Step B ─┼→ Aggregate → Output
162
+ └→ Step C ─┘
163
+ """
164
+
165
+ ## Inngest Example
166
+ """
167
+ export const analyzeDocument = inngest.createFunction(
168
+ { id: "analyze-document" },
169
+ { event: "document/uploaded" },
170
+ async ({ event, step }) => {
171
+ // Run analyses in parallel
172
+ const [security, performance, compliance] = await Promise.all([
173
+ step.run("security-analysis", () =>
174
+ analyzeForSecurityIssues(event.data.document)
175
+ ),
176
+ step.run("performance-analysis", () =>
177
+ analyzeForPerformance(event.data.document)
178
+ ),
179
+ step.run("compliance-analysis", () =>
180
+ analyzeForCompliance(event.data.document)
181
+ ),
182
+ ]);
183
+
184
+ // Aggregate results
185
+ const report = await step.run("generate-report", () =>
186
+ generateReport({ security, performance, compliance })
187
+ );
188
+
189
+ return report;
190
+ }
191
+ );
192
+ """
193
+
194
+ ## AWS Step Functions (Amazon States Language)
195
+ """
196
+ {
197
+ "Type": "Parallel",
198
+ "Branches": [
199
+ {
200
+ "StartAt": "SecurityAnalysis",
201
+ "States": {
202
+ "SecurityAnalysis": {
203
+ "Type": "Task",
204
+ "Resource": "arn:aws:lambda:...:security-analyzer",
205
+ "End": true
206
+ }
207
+ }
208
+ },
209
+ {
210
+ "StartAt": "PerformanceAnalysis",
211
+ "States": {
212
+ "PerformanceAnalysis": {
213
+ "Type": "Task",
214
+ "Resource": "arn:aws:lambda:...:performance-analyzer",
215
+ "End": true
216
+ }
217
+ }
218
+ }
219
+ ],
220
+ "Next": "AggregateResults"
221
+ }
222
+ """
223
+
44
224
  ### Orchestrator-Worker Pattern
45
225
 
46
226
  Central coordinator dispatches work to specialized workers
47
227
 
48
- ## Anti-Patterns
228
+ **When to use**: Complex tasks requiring different expertise, dynamic subtask creation
229
+
230
+ # ORCHESTRATOR-WORKER PATTERN:
231
+
232
+ """
233
+ ┌─────────────────────────────────────┐
234
+ │ ORCHESTRATOR │
235
+ │ - Analyzes task │
236
+ │ - Creates subtasks │
237
+ │ - Dispatches to workers │
238
+ │ - Aggregates results │
239
+ └─────────────────────────────────────┘
240
+
241
+ ┌───────────┼───────────┐
242
+ ▼ ▼ ▼
243
+ ┌───────┐ ┌───────┐ ┌───────┐
244
+ │Worker1│ │Worker2│ │Worker3│
245
+ │Create │ │Modify │ │Delete │
246
+ └───────┘ └───────┘ └───────┘
247
+ """
248
+
249
+ ## Temporal Example
250
+ """
251
+ export async function orchestratorWorkflow(task: ComplexTask) {
252
+ // Orchestrator decides what work needs to be done
253
+ const plan = await analyzeTask(task);
254
+
255
+ // Dispatch to specialized worker workflows
256
+ const results = await Promise.all(
257
+ plan.subtasks.map(subtask => {
258
+ switch (subtask.type) {
259
+ case 'create':
260
+ return executeChild(createWorkerWorkflow, { args: [subtask] });
261
+ case 'modify':
262
+ return executeChild(modifyWorkerWorkflow, { args: [subtask] });
263
+ case 'delete':
264
+ return executeChild(deleteWorkerWorkflow, { args: [subtask] });
265
+ }
266
+ })
267
+ );
268
+
269
+ // Aggregate results
270
+ return aggregateResults(results);
271
+ }
272
+ """
273
+
274
+ ## Inngest with AI Orchestration
275
+ """
276
+ export const aiOrchestrator = inngest.createFunction(
277
+ { id: "ai-orchestrator" },
278
+ { event: "task/complex" },
279
+ async ({ event, step }) => {
280
+ // AI decides what needs to be done
281
+ const plan = await step.run("create-plan", async () => {
282
+ return await llm.chat({
283
+ messages: [
284
+ { role: "system", content: "Break this task into subtasks..." },
285
+ { role: "user", content: event.data.task }
286
+ ]
287
+ });
288
+ });
289
+
290
+ // Execute each subtask as a durable step
291
+ const results = [];
292
+ for (const subtask of plan.subtasks) {
293
+ const result = await step.run(`execute-${subtask.id}`, async () => {
294
+ return executeSubtask(subtask);
295
+ });
296
+ results.push(result);
297
+ }
298
+
299
+ // Final synthesis
300
+ return await step.run("synthesize", async () => {
301
+ return synthesizeResults(results);
302
+ });
303
+ }
304
+ );
305
+ """
306
+
307
+ ### Event-Driven Trigger Pattern
308
+
309
+ Workflows triggered by events, not schedules
310
+
311
+ **When to use**: Reactive systems, user actions, webhook integrations
312
+
313
+ # EVENT-DRIVEN TRIGGERS:
314
+
315
+ ## Inngest Event-Based
316
+ """
317
+ // Define events with TypeScript types
318
+ type Events = {
319
+ "user/signed.up": {
320
+ data: { userId: string; email: string };
321
+ };
322
+ "order/completed": {
323
+ data: { orderId: string; total: number };
324
+ };
325
+ };
326
+
327
+ // Function triggered by event
328
+ export const onboardUser = inngest.createFunction(
329
+ { id: "onboard-user" },
330
+ { event: "user/signed.up" }, // Trigger on this event
331
+ async ({ event, step }) => {
332
+ // Wait 1 hour, then send welcome email
333
+ await step.sleep("wait-for-exploration", "1 hour");
334
+
335
+ await step.run("send-welcome", async () => {
336
+ return sendWelcomeEmail(event.data.email);
337
+ });
338
+
339
+ // Wait 3 days for engagement check
340
+ await step.sleep("wait-for-engagement", "3 days");
341
+
342
+ const engaged = await step.run("check-engagement", async () => {
343
+ return checkUserEngagement(event.data.userId);
344
+ });
345
+
346
+ if (!engaged) {
347
+ await step.run("send-nudge", async () => {
348
+ return sendNudgeEmail(event.data.email);
349
+ });
350
+ }
351
+ }
352
+ );
353
+
354
+ // Send events from anywhere
355
+ await inngest.send({
356
+ name: "user/signed.up",
357
+ data: { userId: "123", email: "user@example.com" }
358
+ });
359
+ """
360
+
361
+ ## n8n Webhook Trigger
362
+ """
363
+ [Webhook: POST /api/webhooks/order]
364
+
365
+ [Switch: event.type]
366
+ ↓ order.created
367
+ [Process New Order Subworkflow]
368
+ ↓ order.cancelled
369
+ [Handle Cancellation Subworkflow]
370
+ """
371
+
372
+ ### Retry and Recovery Pattern
373
+
374
+ Automatic retry with backoff, dead letter handling
375
+
376
+ **When to use**: Any workflow with external dependencies
377
+
378
+ # RETRY AND RECOVERY:
379
+
380
+ ## Temporal Retry Configuration
381
+ """
382
+ const activities = proxyActivities<typeof activitiesType>({
383
+ startToCloseTimeout: '30 seconds',
384
+ retry: {
385
+ initialInterval: '1 second',
386
+ backoffCoefficient: 2,
387
+ maximumInterval: '1 minute',
388
+ maximumAttempts: 5,
389
+ nonRetryableErrorTypes: [
390
+ 'ValidationError', // Don't retry validation failures
391
+ 'InsufficientFunds', // Don't retry payment failures
392
+ ]
393
+ }
394
+ });
395
+ """
396
+
397
+ ## Inngest Retry Configuration
398
+ """
399
+ export const processPayment = inngest.createFunction(
400
+ {
401
+ id: "process-payment",
402
+ retries: 5, // Retry up to 5 times
403
+ },
404
+ { event: "payment/initiated" },
405
+ async ({ event, step, attempt }) => {
406
+ // attempt is 0-indexed retry count
407
+
408
+ const result = await step.run("charge-card", async () => {
409
+ try {
410
+ return await stripe.charges.create({...});
411
+ } catch (error) {
412
+ if (error.code === 'card_declined') {
413
+ // Don't retry card declines
414
+ throw new NonRetriableError("Card declined");
415
+ }
416
+ throw error; // Retry other errors
417
+ }
418
+ });
419
+
420
+ return result;
421
+ }
422
+ );
423
+ """
424
+
425
+ ## Dead Letter Handling
426
+ """
427
+ // n8n: Use Error Trigger node
428
+ [Error Trigger]
429
+
430
+ [Log to Error Database]
431
+
432
+ [Send Alert to Slack]
433
+
434
+ [Create Ticket in Jira]
435
+
436
+ // Inngest: Handle in onFailure
437
+ export const myFunction = inngest.createFunction(
438
+ {
439
+ id: "my-function",
440
+ onFailure: async ({ error, event, step }) => {
441
+ await step.run("alert-team", async () => {
442
+ await slack.postMessage({
443
+ channel: "#errors",
444
+ text: `Function failed: ${error.message}`
445
+ });
446
+ });
447
+ }
448
+ },
449
+ { event: "..." },
450
+ async ({ step }) => { ... }
451
+ );
452
+ """
453
+
454
+ ### Scheduled Workflow Pattern
455
+
456
+ Time-based triggers for recurring tasks
457
+
458
+ **When to use**: Daily reports, periodic sync, batch processing
459
+
460
+ # SCHEDULED WORKFLOWS:
461
+
462
+ ## Inngest Cron
463
+ """
464
+ export const dailyReport = inngest.createFunction(
465
+ { id: "daily-report" },
466
+ { cron: "0 9 * * *" }, // Every day at 9 AM
467
+ async ({ step }) => {
468
+ const data = await step.run("gather-metrics", async () => {
469
+ return gatherDailyMetrics();
470
+ });
471
+
472
+ await step.run("generate-report", async () => {
473
+ return generateAndSendReport(data);
474
+ });
475
+ }
476
+ );
477
+
478
+ export const syncInventory = inngest.createFunction(
479
+ { id: "sync-inventory" },
480
+ { cron: "*/15 * * * *" }, // Every 15 minutes
481
+ async ({ step }) => {
482
+ await step.run("sync", async () => {
483
+ return syncWithSupplier();
484
+ });
485
+ }
486
+ );
487
+ """
488
+
489
+ ## Temporal Cron Workflow
490
+ """
491
+ // Schedule workflow to run on cron
492
+ const handle = await client.workflow.start(dailyReportWorkflow, {
493
+ taskQueue: 'reports',
494
+ workflowId: 'daily-report',
495
+ cronSchedule: '0 9 * * *', // 9 AM daily
496
+ });
497
+ """
498
+
499
+ ## n8n Schedule Trigger
500
+ """
501
+ [Schedule Trigger: Every day at 9:00 AM]
502
+
503
+ [HTTP Request: Get Metrics]
504
+
505
+ [Code Node: Generate Report]
506
+
507
+ [Send Email: Report]
508
+ """
509
+
510
+ ## Sharp Edges
511
+
512
+ ### Non-Idempotent Steps in Durable Workflows
513
+
514
+ Severity: CRITICAL
515
+
516
+ Situation: Writing workflow steps that modify external state
517
+
518
+ Symptoms:
519
+ Customer charged twice. Email sent three times. Database record
520
+ created multiple times. Workflow retries cause duplicate side effects.
521
+
522
+ Why this breaks:
523
+ Durable execution replays workflows from the beginning on restart.
524
+ If step 3 crashes and the workflow resumes, steps 1 and 2 run again.
525
+ Without idempotency keys, external services don't know these are retries.
526
+
527
+ Recommended fix:
528
+
529
+ # ALWAYS use idempotency keys for external calls:
530
+
531
+ ## Stripe example:
532
+ await stripe.paymentIntents.create({
533
+ amount: 1000,
534
+ currency: 'usd',
535
+ idempotency_key: `order-${orderId}-payment` # Critical!
536
+ });
537
+
538
+ ## Email example:
539
+ await step.run("send-confirmation", async () => {
540
+ const alreadySent = await checkEmailSent(orderId);
541
+ if (alreadySent) return { skipped: true };
542
+ return sendEmail(customer, orderId);
543
+ });
544
+
545
+ ## Database example:
546
+ await db.query(`
547
+ INSERT INTO orders (id, ...) VALUES ($1, ...)
548
+ ON CONFLICT (id) DO NOTHING
549
+ `, [orderId]);
550
+
551
+ # Generate idempotency key from stable inputs, not random values
552
+
553
+ ### Workflow Runs for Hours/Days Without Checkpoints
554
+
555
+ Severity: HIGH
556
+
557
+ Situation: Long-running workflows with infrequent steps
558
+
559
+ Symptoms:
560
+ Memory consumption grows. Worker timeouts. Lost progress after
561
+ crashes. "Workflow exceeded maximum duration" errors.
562
+
563
+ Why this breaks:
564
+ Workflows hold state in memory until checkpointed. A workflow that
565
+ runs for 24 hours with one step per hour accumulates state for 24h.
566
+ Workers have memory limits. Functions have execution time limits.
567
+
568
+ Recommended fix:
569
+
570
+ # Break long workflows into checkpointed steps:
571
+
572
+ ## WRONG - one long step:
573
+ await step.run("process-all", async () => {
574
+ for (const item of thousandItems) {
575
+ await processItem(item); // Hours of work, one checkpoint
576
+ }
577
+ });
578
+
579
+ ## CORRECT - many small steps:
580
+ for (const item of thousandItems) {
581
+ await step.run(`process-${item.id}`, async () => {
582
+ return processItem(item); // Checkpoint after each
583
+ });
584
+ }
585
+
586
+ ## For very long waits, use sleep:
587
+ await step.sleep("wait-for-trial", "14 days");
588
+ // Doesn't consume resources while waiting
589
+
590
+ ## Consider child workflows for long processes:
591
+ await step.invoke("process-batch", {
592
+ function: batchProcessor,
593
+ data: { items: batch }
594
+ });
595
+
596
+ ### Activities Without Timeout Configuration
597
+
598
+ Severity: HIGH
599
+
600
+ Situation: Calling external services from workflow activities
601
+
602
+ Symptoms:
603
+ Workflows hang indefinitely. Worker pool exhausted. Dead workflows
604
+ that never complete or fail. Manual intervention needed to kill stuck
605
+ workflows.
606
+
607
+ Why this breaks:
608
+ External APIs can hang forever. Without timeout, your workflow waits
609
+ forever. Unlike HTTP clients, workflow activities don't have default
610
+ timeouts in most platforms.
611
+
612
+ Recommended fix:
613
+
614
+ # ALWAYS set timeouts on activities:
615
+
616
+ ## Temporal:
617
+ const activities = proxyActivities<typeof activitiesType>({
618
+ startToCloseTimeout: '30 seconds', # Required!
619
+ scheduleToCloseTimeout: '5 minutes',
620
+ heartbeatTimeout: '10 seconds', # For long activities
621
+ retry: {
622
+ maximumAttempts: 3,
623
+ initialInterval: '1 second',
624
+ }
625
+ });
626
+
627
+ ## Inngest:
628
+ await step.run("call-api", { timeout: "30s" }, async () => {
629
+ return fetch(url, { signal: AbortSignal.timeout(25000) });
630
+ });
631
+
632
+ ## AWS Step Functions:
633
+ {
634
+ "Type": "Task",
635
+ "TimeoutSeconds": 30,
636
+ "HeartbeatSeconds": 10,
637
+ "Resource": "arn:aws:lambda:..."
638
+ }
639
+
640
+ # Rule: Activity timeout < Workflow timeout
641
+
642
+ ### Side Effects Outside Step/Activity Boundaries
643
+
644
+ Severity: CRITICAL
645
+
646
+ Situation: Writing code that runs during workflow replay
647
+
648
+ Symptoms:
649
+ Random failures on replay. "Workflow corrupted" errors. Different
650
+ behavior on replay than initial run. Non-determinism errors.
49
651
 
50
- ### No Durable Execution for Payments
652
+ Why this breaks:
653
+ Workflow code runs on EVERY replay. If you generate a random ID in
654
+ workflow code, you get a different ID each replay. If you read the
655
+ current time, you get a different time. This breaks determinism.
51
656
 
52
- ### ❌ Monolithic Workflows
657
+ Recommended fix:
53
658
 
54
- ### No Observability
659
+ # WRONG - side effects in workflow code:
660
+ export async function orderWorkflow(order) {
661
+ const orderId = uuid(); // Different every replay!
662
+ const now = new Date(); // Different every replay!
663
+ await activities.process(orderId, now);
664
+ }
55
665
 
56
- ## ⚠️ Sharp Edges
666
+ # CORRECT - side effects in activities:
667
+ export async function orderWorkflow(order) {
668
+ const orderId = await activities.generateOrderId(); # Recorded
669
+ const now = await activities.getCurrentTime(); # Recorded
670
+ await activities.process(orderId, now);
671
+ }
57
672
 
58
- | Issue | Severity | Solution |
59
- |-------|----------|----------|
60
- | Issue | critical | # ALWAYS use idempotency keys for external calls: |
61
- | Issue | high | # Break long workflows into checkpointed steps: |
62
- | Issue | high | # ALWAYS set timeouts on activities: |
63
- | Issue | critical | # WRONG - side effects in workflow code: |
64
- | Issue | medium | # ALWAYS use exponential backoff: |
65
- | Issue | high | # WRONG - large data in workflow: |
66
- | Issue | high | # Inngest onFailure handler: |
67
- | Issue | medium | # Every production n8n workflow needs: |
673
+ # Also CORRECT - Temporal workflow.now() and sideEffect:
674
+ import { sideEffect } from '@temporalio/workflow';
675
+
676
+ const orderId = await sideEffect(() => uuid());
677
+ const now = workflow.now(); # Deterministic replay-safe time
678
+
679
+ # Side effects that are safe in workflow code:
680
+ # - Reading function arguments
681
+ # - Simple calculations (no randomness)
682
+ # - Logging (usually)
683
+
684
+ ### Retry Configuration Without Exponential Backoff
685
+
686
+ Severity: MEDIUM
687
+
688
+ Situation: Configuring retry behavior for failing steps
689
+
690
+ Symptoms:
691
+ Overwhelming failing services. Rate limiting. Cascading failures.
692
+ Retry storms causing outages. Being blocked by external APIs.
693
+
694
+ Why this breaks:
695
+ When a service is struggling, immediate retries make it worse.
696
+ 100 workflows retrying instantly = 100 requests hitting a service
697
+ that's already failing. Backoff gives the service time to recover.
698
+
699
+ Recommended fix:
700
+
701
+ # ALWAYS use exponential backoff:
702
+
703
+ ## Temporal:
704
+ const activities = proxyActivities({
705
+ retry: {
706
+ initialInterval: '1 second',
707
+ backoffCoefficient: 2, # 1s, 2s, 4s, 8s, 16s...
708
+ maximumInterval: '1 minute', # Cap the backoff
709
+ maximumAttempts: 5,
710
+ }
711
+ });
712
+
713
+ ## Inngest (built-in backoff):
714
+ {
715
+ id: "my-function",
716
+ retries: 5, # Uses exponential backoff by default
717
+ }
718
+
719
+ ## Manual backoff:
720
+ const backoff = (attempt) => {
721
+ const base = 1000;
722
+ const max = 60000;
723
+ const delay = Math.min(base * Math.pow(2, attempt), max);
724
+ const jitter = delay * 0.1 * Math.random();
725
+ return delay + jitter;
726
+ };
727
+
728
+ # Add jitter to prevent thundering herd
729
+
730
+ ### Storing Large Data in Workflow State
731
+
732
+ Severity: HIGH
733
+
734
+ Situation: Passing large payloads between workflow steps
735
+
736
+ Symptoms:
737
+ Slow workflow execution. Memory errors. "Payload too large" errors.
738
+ Expensive storage costs. Slow replays.
739
+
740
+ Why this breaks:
741
+ Workflow state is persisted and replayed. A 10MB payload is stored,
742
+ serialized, and deserialized on every step. This adds latency and
743
+ cost. Some platforms have hard limits (e.g., Step Functions 256KB).
744
+
745
+ Recommended fix:
746
+
747
+ # WRONG - large data in workflow:
748
+ await step.run("fetch-data", async () => {
749
+ const largeDataset = await fetchAllRecords(); // 100MB!
750
+ return largeDataset; // Stored in workflow state
751
+ });
752
+
753
+ # CORRECT - store reference, not data:
754
+ await step.run("fetch-data", async () => {
755
+ const largeDataset = await fetchAllRecords();
756
+ const s3Key = await uploadToS3(largeDataset);
757
+ return { s3Key }; // Just the reference
758
+ });
759
+
760
+ const processed = await step.run("process-data", async () => {
761
+ const data = await downloadFromS3(fetchResult.s3Key);
762
+ return processData(data);
763
+ });
764
+
765
+ # For Step Functions, use S3 for large payloads:
766
+ {
767
+ "Type": "Task",
768
+ "Resource": "arn:aws:states:::s3:putObject",
769
+ "Parameters": {
770
+ "Bucket": "my-bucket",
771
+ "Key.$": "$.outputKey",
772
+ "Body.$": "$.largeData"
773
+ }
774
+ }
775
+
776
+ ### Missing Dead Letter Queue or Failure Handler
777
+
778
+ Severity: HIGH
779
+
780
+ Situation: Workflows that exhaust all retries
781
+
782
+ Symptoms:
783
+ Failed workflows silently disappear. No alerts when things break.
784
+ Customer issues discovered days later. Manual recovery impossible.
785
+
786
+ Why this breaks:
787
+ Even with retries, some workflows will fail permanently. Without
788
+ dead letter handling, you don't know they failed. The customer
789
+ waits forever, you're unaware, and there's no data to debug.
790
+
791
+ Recommended fix:
792
+
793
+ # Inngest onFailure handler:
794
+ export const myFunction = inngest.createFunction(
795
+ {
796
+ id: "process-order",
797
+ onFailure: async ({ error, event, step }) => {
798
+ // Log to error tracking
799
+ await step.run("log-error", () =>
800
+ sentry.captureException(error, { extra: { event } })
801
+ );
802
+
803
+ // Alert team
804
+ await step.run("alert", () =>
805
+ slack.postMessage({
806
+ channel: "#alerts",
807
+ text: `Order ${event.data.orderId} failed: ${error.message}`
808
+ })
809
+ );
810
+
811
+ // Queue for manual review
812
+ await step.run("queue-review", () =>
813
+ db.insert(failedOrders, { orderId, error, event })
814
+ );
815
+ }
816
+ },
817
+ { event: "order/created" },
818
+ async ({ event, step }) => { ... }
819
+ );
820
+
821
+ # n8n Error Trigger:
822
+ [Error Trigger] → [Log to DB] → [Slack Alert] → [Create Ticket]
823
+
824
+ # Temporal: Use workflow.failed or workflow signals
825
+
826
+ ### n8n Workflow Without Error Trigger
827
+
828
+ Severity: MEDIUM
829
+
830
+ Situation: Building production n8n workflows
831
+
832
+ Symptoms:
833
+ Workflow fails silently. Errors only visible in execution logs.
834
+ No alerts, no recovery, no visibility until someone notices.
835
+
836
+ Why this breaks:
837
+ n8n doesn't notify on failure by default. Without an Error Trigger
838
+ node connected to alerting, failures are only visible in the UI.
839
+ Production failures go unnoticed.
840
+
841
+ Recommended fix:
842
+
843
+ # Every production n8n workflow needs:
844
+
845
+ 1. Error Trigger node
846
+ - Catches any node failure in the workflow
847
+ - Provides error details and context
848
+
849
+ 2. Connected error handling:
850
+ [Error Trigger]
851
+
852
+ [Set: Extract Error Details]
853
+
854
+ [HTTP: Log to Error Service]
855
+
856
+ [Slack/Email: Alert Team]
857
+
858
+ 3. Consider dead letter pattern:
859
+ [Error Trigger]
860
+
861
+ [Redis/Postgres: Store Failed Job]
862
+
863
+ [Separate Recovery Workflow]
864
+
865
+ # Also use:
866
+ - Retry on node failures (built-in)
867
+ - Node timeout settings
868
+ - Workflow timeout
869
+
870
+ ### Long-Running Temporal Activities Without Heartbeat
871
+
872
+ Severity: MEDIUM
873
+
874
+ Situation: Activities that run for more than a few seconds
875
+
876
+ Symptoms:
877
+ Activity timeouts even when work is progressing. Lost work when
878
+ workers restart. Can't cancel long-running activities.
879
+
880
+ Why this breaks:
881
+ Temporal detects stuck activities via heartbeat. Without heartbeat,
882
+ Temporal can't tell if activity is working or stuck. Long activities
883
+ appear hung, may timeout, and can't be gracefully cancelled.
884
+
885
+ Recommended fix:
886
+
887
+ # For any activity > 10 seconds, add heartbeat:
888
+
889
+ import { heartbeat, activityInfo } from '@temporalio/activity';
890
+
891
+ export async function processLargeFile(fileUrl: string): Promise<void> {
892
+ const chunks = await downloadChunks(fileUrl);
893
+
894
+ for (let i = 0; i < chunks.length; i++) {
895
+ // Check for cancellation
896
+ const { cancelled } = activityInfo();
897
+ if (cancelled) {
898
+ throw new CancelledFailure('Activity cancelled');
899
+ }
900
+
901
+ await processChunk(chunks[i]);
902
+
903
+ // Report progress
904
+ heartbeat({ progress: (i + 1) / chunks.length });
905
+ }
906
+ }
907
+
908
+ # Configure heartbeat timeout:
909
+ const activities = proxyActivities({
910
+ startToCloseTimeout: '10 minutes',
911
+ heartbeatTimeout: '30 seconds', # Must heartbeat every 30s
912
+ });
913
+
914
+ # If no heartbeat for 30s, activity is considered stuck
915
+
916
+ ## Validation Checks
917
+
918
+ ### External Calls Without Idempotency Key
919
+
920
+ Severity: ERROR
921
+
922
+ Stripe/payment calls should use idempotency keys
923
+
924
+ Message: Payment call without idempotency_key. Add idempotency key to prevent duplicate charges on retry.
925
+
926
+ ### Email Sending Without Deduplication
927
+
928
+ Severity: WARNING
929
+
930
+ Email sends in workflows should check for already-sent
931
+
932
+ Message: Email sent in workflow without deduplication check. Retries may send duplicate emails.
933
+
934
+ ### Temporal Activities Without Timeout
935
+
936
+ Severity: ERROR
937
+
938
+ All Temporal activities need timeout configuration
939
+
940
+ Message: proxyActivities without timeout. Add startToCloseTimeout to prevent indefinite hangs.
941
+
942
+ ### Inngest Steps Calling External APIs Without Timeout
943
+
944
+ Severity: WARNING
945
+
946
+ External API calls should have timeouts
947
+
948
+ Message: External API call in step without timeout. Add timeout to prevent workflow hangs.
949
+
950
+ ### Random Values in Workflow Code
951
+
952
+ Severity: ERROR
953
+
954
+ Random values break determinism on replay
955
+
956
+ Message: Random value in workflow code. Move to activity/step or use sideEffect.
957
+
958
+ ### Date.now() in Workflow Code
959
+
960
+ Severity: ERROR
961
+
962
+ Current time breaks determinism on replay
963
+
964
+ Message: Current time in workflow code. Use workflow.now() or move to activity/step.
965
+
966
+ ### Inngest Function Without onFailure Handler
967
+
968
+ Severity: WARNING
969
+
970
+ Production functions should have failure handlers
971
+
972
+ Message: Inngest function without onFailure handler. Add failure handling for production reliability.
973
+
974
+ ### Step Without Error Handling
975
+
976
+ Severity: WARNING
977
+
978
+ Steps should handle errors gracefully
979
+
980
+ Message: Step without try/catch. Consider handling specific error cases.
981
+
982
+ ### Potentially Large Data Returned from Step
983
+
984
+ Severity: INFO
985
+
986
+ Large data in workflow state slows execution
987
+
988
+ Message: Returning potentially large data from step. Consider storing in S3/DB and returning reference.
989
+
990
+ ### Retry Without Backoff Configuration
991
+
992
+ Severity: WARNING
993
+
994
+ Retries should use exponential backoff
995
+
996
+ Message: Retry configured without backoff. Add backoffCoefficient and initialInterval.
997
+
998
+ ## Collaboration
999
+
1000
+ ### Delegation Triggers
1001
+
1002
+ - user needs multi-agent coordination -> multi-agent-orchestration (Workflow provides infrastructure, orchestration provides patterns)
1003
+ - user needs tool building for workflows -> agent-tool-builder (Tools that workflows can invoke)
1004
+ - user needs Zapier/Make integration -> zapier-make-patterns (No-code automation platforms)
1005
+ - user needs browser automation in workflow -> browser-automation (Playwright/Puppeteer activities)
1006
+ - user needs computer control in workflow -> computer-use-agents (Desktop automation activities)
1007
+ - user needs LLM integration in workflow -> llm-architect (AI-powered workflow steps)
68
1008
 
69
1009
  ## Related Skills
70
1010
 
71
- Works well with: `multi-agent-orchestration`, `agent-tool-builder`, `backend`, `devops`, `dbos-*`
1011
+ Works well with: `multi-agent-orchestration`, `agent-tool-builder`, `backend`, `devops`
72
1012
 
73
1013
  ## When to Use
74
- This skill is applicable to execute the workflow or actions described in the overview.
1014
+
1015
+ - User mentions or implies: workflow
1016
+ - User mentions or implies: automation
1017
+ - User mentions or implies: n8n
1018
+ - User mentions or implies: temporal
1019
+ - User mentions or implies: inngest
1020
+ - User mentions or implies: step function
1021
+ - User mentions or implies: background job
1022
+ - User mentions or implies: durable execution
1023
+ - User mentions or implies: event-driven
1024
+ - User mentions or implies: scheduled task
1025
+ - User mentions or implies: job queue
1026
+ - User mentions or implies: cron
1027
+ - User mentions or implies: trigger