{"id":"c705c280-1c1b-40da-b290-4ab0da12a38e","shortId":"GR2Ew2","kind":"skill","title":"inngest-steps","tagline":"Use when implementing delays that must survive process restarts (e.g., 24-hour cart abandonment, scheduled follow-ups), waiting for human approval or external events with timeouts (review gates, webhook callbacks, async API completion), polling external services without losing st","description":"# Inngest Steps\n\nBuild robust, durable workflows with Inngest's step methods. Each step is a separate HTTP request that can be independently retried and monitored.\n\n> **These skills are focused on TypeScript.** For Python or Go, refer to the [Inngest documentation](https://www.inngest.com/llms.txt) for language-specific guidance. Core concepts apply across all languages.\n\n## Core Concept\n\n**🔄 Critical: Each step re-runs your function from the beginning.** Put ALL non-deterministic code (API calls, DB queries, randomness) inside steps, never outside.\n\n**📊 Step Limits:** Every function has a maximum of 1,000 steps and 4MB total step data.\n\n```typescript\n// ❌ WRONG - will run 4 times\nexport default inngest.createFunction(\n  { id: \"bad-example\", triggers: [{ event: \"test\" }] },\n  async ({ step }) => {\n    console.log(\"This logs 4 times!\"); // Outside step = bad\n    await step.run(\"a\", () => console.log(\"a\"));\n    await step.run(\"b\", () => console.log(\"b\"));\n    await step.run(\"c\", () => console.log(\"c\"));\n  }\n);\n\n// ✅ CORRECT - logs once each\nexport default inngest.createFunction(\n  { id: \"good-example\", triggers: [{ event: \"test\" }] },\n  async ({ step }) => {\n    await step.run(\"log-hello\", () => console.log(\"hello\"));\n    await step.run(\"a\", () => console.log(\"a\"));\n    await step.run(\"b\", () => console.log(\"b\"));\n    await step.run(\"c\", () => console.log(\"c\"));\n  }\n);\n```\n\n## step.run()\n\nExecute retriable code as a step. **Each step ID can be reused** - Inngest automatically handles counters.\n\n```typescript\n// Basic usage\nconst result = await step.run(\"fetch-user\", async () => {\n  const user = await db.user.findById(userId);\n  return user; // Always return useful data\n});\n\n// Synchronous code works too\nconst transformed = await step.run(\"transform-data\", () => {\n  return processData(result);\n});\n\n// Side effects (no return needed)\nawait step.run(\"send-notification\", async () => {\n  await sendEmail(user.email, \"Welcome!\");\n});\n```\n\n**✅ DO:**\n\n- Put ALL non-deterministic logic inside steps\n- Return useful data for subsequent steps\n- Reuse step IDs in loops (counters handled automatically)\n\n**❌ DON'T:**\n\n- Put deterministic logic in steps unnecessarily\n- Forget that each step = separate HTTP request\n\n## step.sleep()\n\nPause execution without using compute time.\n\n```typescript\n// Duration strings\nawait step.sleep(\"wait-24h\", \"24h\");\nawait step.sleep(\"short-delay\", \"30s\");\nawait step.sleep(\"weekly-pause\", \"7d\");\n\n// Use in workflows\nawait step.run(\"send-welcome\", () => sendEmail(email));\nawait step.sleep(\"wait-for-engagement\", \"3d\");\nawait step.run(\"send-followup\", () => sendFollowupEmail(email));\n```\n\n## step.sleepUntil()\n\nSleep until a specific datetime.\n\n```typescript\nconst reminderDate = new Date(\"2024-12-25T09:00:00Z\");\nawait step.sleepUntil(\"wait-for-christmas\", reminderDate);\n\n// From event data\nconst scheduledTime = new Date(event.data.remind_at);\nawait step.sleepUntil(\"wait-for-scheduled-time\", scheduledTime);\n```\n\n## step.waitForEvent()\n\n**🚨 CRITICAL: waitForEvent ONLY catches events sent AFTER this step executes.**\n\n- ❌ Event sent before waitForEvent runs → will NOT be caught\n- ✅ Event sent after waitForEvent runs → will be caught\n- Always check for `null` return (means timeout, event never arrived)\n\n```typescript\n// Basic event waiting with timeout\nconst approval = await step.waitForEvent(\"wait-for-approval\", {\n  event: \"app/invoice.approved\",\n  timeout: \"7d\",\n  match: \"data.invoiceId\" // Simple matching\n});\n\n// Expression-based matching (CEL syntax)\nconst subscription = await step.waitForEvent(\"wait-for-subscription\", {\n  event: \"app/subscription.created\",\n  timeout: \"30d\",\n  if: \"event.data.userId == async.data.userId && async.data.plan == 'pro'\"\n});\n\n// Handle timeout\nif (!approval) {\n  await step.run(\"handle-timeout\", () => {\n    // Approval never came\n    return notifyAccountingTeam();\n  });\n}\n```\n\n**✅ DO:**\n\n- Use unique IDs for matching (userId, sessionId, requestId)\n- Always set reasonable timeouts\n- Handle null return (timeout case)\n- Use with Realtime for human-in-the-loop flows\n\n**❌ DON'T:**\n\n- Expect events sent before this step to be handled\n- Use without timeouts in production\n\n### Expression Syntax\n\nIn expressions, `event` = the **original** triggering event, `async` = the **new** event being matched. See [Expression Syntax Reference](../references/expressions.md) for full syntax, operators, and patterns.\n\n## step.waitForSignal()\n\nWait for unique signals (not events). Better for 1:1 matching.\n\n```typescript\nconst taskId = \"task-\" + crypto.randomUUID();\n\nconst signal = await step.waitForSignal(\"wait-for-task-completion\", {\n  signal: taskId,\n  timeout: \"1h\",\n  onConflict: \"replace\" // Required: \"replace\" overwrites pending signal, \"fail\" throws an error\n});\n\n// Send signal elsewhere via Inngest API or SDK\n// POST /v1/events with signal matching taskId\n```\n\n**When to use:**\n\n- **waitForEvent**: Multiple functions might handle the same event\n- **waitForSignal**: Exact 1:1 signal to specific function run\n\n## step.sendEvent()\n\nFan out to other functions without waiting for results.\n\n```typescript\n// Trigger other functions\nawait step.sendEvent(\"notify-systems\", {\n  name: \"user/profile.updated\",\n  data: { userId: user.id, changes: profileChanges }\n});\n\n// Multiple events at once\nawait step.sendEvent(\"batch-notifications\", [\n  { name: \"billing/invoice.created\", data: { invoiceId } },\n  { name: \"email/invoice.send\", data: { email: user.email, invoiceId } }\n]);\n```\n\n**Use when:** You want to trigger other functions but don't need their results in the current function.\n\n## step.invoke()\n\nCall other functions and handle their results. Perfect for composition.\n\n```typescript\nconst computeSquare = inngest.createFunction(\n  { id: \"compute-square\", triggers: [{ event: \"calculate/square\" }] },\n  async ({ event }) => {\n    return { result: event.data.number * event.data.number };\n  }\n);\n\n// Invoke and use result\nconst square = await step.invoke(\"get-square\", {\n  function: computeSquare,\n  data: { number: 4 }\n});\n\nconsole.log(square.result); // 16, fully typed!\n\n// For cross-app invocation (when you can't import the function directly):\nimport { referenceFunction } from \"inngest\";\n\nconst externalFn = referenceFunction({\n  appId: \"other-app\",\n  functionId: \"other-fn\"\n});\n\nconst result = await step.invoke(\"call-external\", {\n  function: externalFn,\n  data: { key: \"value\" }\n});\n```\n\n**Warning: v4 Breaking Change:** String function IDs (e.g., `function: \"my-app-other-fn\"`) are no longer supported in `step.invoke()`. Use an imported function reference or `referenceFunction()` for cross-app calls.\n\n**Great for:**\n\n- Breaking complex workflows into composable functions\n- Reusing logic across multiple workflows\n- Map-reduce patterns\n\n## Patterns\n\n### Loops with Steps\n\nReuse step IDs - Inngest handles counters automatically.\n\n```typescript\nconst allProducts = [];\nlet cursor = null;\nlet hasMore = true;\n\nwhile (hasMore) {\n  // Same ID \"fetch-page\" reused - counters handled automatically\n  const page = await step.run(\"fetch-page\", async () => {\n    return shopify.products.list({ cursor, limit: 50 });\n  });\n\n  allProducts.push(...page.products);\n\n  if (page.products.length < 50) {\n    hasMore = false;\n  } else {\n    cursor = page.products[49].id;\n  }\n}\n\nawait step.run(\"process-products\", () => {\n  return processAllProducts(allProducts);\n});\n```\n\n### Parallel Execution\n\nUse Promise.all for parallel steps. **In v4, parallel step execution is optimized by default**\n\n```typescript\n// Create steps without awaiting\nconst sendEmail = step.run(\"send-email\", async () => {\n  return await sendWelcomeEmail(user.email);\n});\n\nconst updateCRM = step.run(\"update-crm\", async () => {\n  return await crmService.addUser(user);\n});\n\nconst createSubscription = step.run(\"create-subscription\", async () => {\n  return await subscriptionService.create(user.id);\n});\n\n// Run all in parallel\nconst [emailId, crmRecord, subscription] = await Promise.all([\n  sendEmail,\n  updateCRM,\n  createSubscription\n]);\n\n// Parallel steps are optimized by default in v4\nexport default inngest.createFunction(\n  {\n    id: \"parallel-heavy-function\",\n    triggers: [{ event: \"process/batch\" }]\n  },\n  async ({ event, step }) => {\n    const results = await Promise.all(\n      event.data.items.map((item, i) =>\n        step.run(`process-item-${i}`, () => processItem(item))\n      )\n    );\n  }\n);\n\n// ⚠️ Promise.race() behavior with v4's optimized parallelism:\n// All promises settle before race resolves. Use group.parallel() for true race:\nconst winner = await group.parallel(async () => {\n  return Promise.race([\n    step.run(\"fast-service\", () => callFastService()),\n    step.run(\"slow-service\", () => callSlowService())\n  ]);\n});\n\n// To disable optimized parallelism if needed:\n// At the client level: new Inngest({ id: \"app\", optimizeParallelism: false })\n// At the function level: { id: \"fn\", optimizeParallelism: false, triggers: [...] }\n```\n\nSee **inngest-flow-control** for concurrency and throttling options.\n\n### Chunking Jobs\n\nPerfect for batch processing with parallel steps.\n\n```typescript\nexport default inngest.createFunction(\n  { id: \"process-large-dataset\", triggers: [{ event: \"data/process.large\" }] },\n  async ({ event, step }) => {\n    const chunks = chunkArray(event.data.items, 10);\n\n    // Process chunks in parallel\n    const results = await Promise.all(\n      chunks.map((chunk, index) =>\n        step.run(`process-chunk-${index}`, () => processChunk(chunk))\n      )\n    );\n\n    // Combine results\n    await step.run(\"combine-results\", () => {\n      return aggregateResults(results);\n    });\n  }\n);\n```\n\n## Key Gotchas\n\n**🔄 Function Re-execution:** Code outside steps runs on every step execution\n**⏰ Event Timing:** waitForEvent only catches events sent AFTER the step runs\n**🔢 Step Limits:** Max 1,000 steps per function, 4MB per step output, 32MB per function run in total\n**📨 HTTP Requests:** Checkpointing is enabled by default in v4, reducing HTTP overhead. For serverless platforms, configure `maxRuntime` on the client\n**🔁 Step IDs:** Can be reused in loops - Inngest handles counters\n**⚡ Parallelism:** Use Promise.all for parallel steps (optimized by default in v4). Note that Promise.race() waits for all promises to settle — use `group.parallel()` for true race semantics\n\n## Common Use Cases\n\n- **Human-in-the-loop:** waitForEvent + Realtime UI\n- **Multi-step onboarding:** sleep between steps, waitForEvent for user actions\n- **Data processing:** Parallel steps for chunked work\n- **External integrations:** step.run for reliable API calls\n- **AI workflows:** step.ai for durable LLM orchestration\n- **Function composition:** step.invoke to build complex workflows\n\nRemember: Steps make your functions durable, observable, and debuggable. Embrace them!","tags":["inngest","steps","skills","agent-skill-repository","agent-skills","agentic-skills","ai-agents","claude-code-skills","cursor-skills","openclaw-skills"],"capabilities":["skill","source-inngest","skill-inngest-steps","topic-agent-skill-repository","topic-agent-skills","topic-agentic-skills","topic-ai-agents","topic-claude-code-skills","topic-cursor-skills","topic-openclaw-skills"],"categories":["inngest-skills"],"synonyms":[],"warnings":[],"endpointUrl":"https://skills.sh/inngest/inngest-skills/inngest-steps","protocol":"skill","transport":"skills-sh","auth":{"type":"none","details":{"cli":"npx skills add inngest/inngest-skills","source_repo":"https://github.com/inngest/inngest-skills","install_from":"skills.sh"}},"qualityScore":"0.461","qualityRationale":"deterministic score 0.46 from registry signals: · indexed on github topic:agent-skills · 22 github stars · SKILL.md body (10,787 chars)","verified":false,"liveness":"unknown","lastLivenessCheck":null,"agentReviews":{"count":0,"score_avg":null,"cost_usd_avg":null,"success_rate":null,"latency_p50_ms":null,"narrative_summary":null,"summary_updated_at":null},"enrichmentModel":"deterministic:skill-github:v1","enrichmentVersion":1,"enrichedAt":"2026-05-18T19:05:31.655Z","embedding":null,"createdAt":"2026-04-18T23:06:59.748Z","updatedAt":"2026-05-18T19:05:31.655Z","lastSeenAt":"2026-05-18T19:05:31.655Z","tsv":"'-12':391 '-25':392 '/llms.txt)':86 '/references/expressions.md':580 '/v1/events':637 '00':394 '000':135,1186 '00z':395 '1':134,596,597,655,656,1185 '10':1128 '16':771 '1h':616 '2024':390 '24':14 '24h':341,342 '30d':497 '30s':348 '32mb':1194 '3d':371 '4':146,163,768 '49':917 '4mb':138,1190 '50':906,911 '7d':354,475 'abandon':17 'across':95,856 'action':1277 'aggregateresult':1155 'ai':1292 'allproduct':876,926 'allproducts.push':907 'alway':256,448,526 'api':36,117,633,1290 'app':777,797,825,844,1078 'app/invoice.approved':473 'app/subscription.created':495 'appid':794 'appli':94 'approv':25,465,471,506,512 'arriv':457 'async':35,158,197,248,284,570,747,901,954,965,976,1013,1052,1121 'async.data.plan':501 'async.data.userid':500 'automat':235,311,873,893 'await':168,173,178,199,206,211,216,243,251,266,279,285,337,343,349,358,365,372,396,412,466,488,507,606,676,692,759,804,896,919,947,956,967,978,989,1018,1050,1135,1149 'b':175,177,213,215 'bad':153,167 'bad-exampl':152 'base':482 'basic':239,459 'batch':695,1104 'batch-notif':694 'begin':110 'behavior':1031 'better':594 'billing/invoice.created':698 'break':816,848 'build':46,1303 'c':180,182,218,220 'calculate/square':746 'call':118,726,807,845,1291 'call-extern':806 'callback':34 'callfastservic':1059 'callslowservic':1064 'came':514 'cart':16 'case':534,1258 'catch':424,1175 'caught':439,447 'cel':484 'chang':686,817 'check':449 'checkpoint':1202 'christma':401 'chunk':1100,1125,1130,1138,1143,1146,1283 'chunkarray':1126 'chunks.map':1137 'client':1073,1219 'code':116,224,261,1163 'combin':1147,1152 'combine-result':1151 'common':1256 'complet':37,612 'complex':849,1304 'compos':852 'composit':735,1300 'comput':332,742 'compute-squar':741 'computesquar':738,765 'concept':93,99 'concurr':1096 'configur':1215 'console.log':160,171,176,181,204,209,214,219,769 'const':241,249,264,386,406,464,486,600,604,737,757,791,802,875,894,948,959,970,985,1016,1048,1124,1133 'control':1094 'core':92,98 'correct':183 'counter':237,309,872,891,1229 'creat':944,974 'create-subscript':973 'createsubscript':971,993 'critic':100,421 'crm':964 'crmrecord':987 'crmservice.adduser':968 'cross':776,843 'cross-app':775,842 'crypto.randomuuid':603 'current':723 'cursor':878,904,915 'data':141,259,270,300,405,683,699,703,766,811,1278 'data.invoiceid':477 'data/process.large':1120 'dataset':1117 'date':389,409 'datetim':384 'db':119 'db.user.findbyid':252 'debugg':1314 'default':149,188,942,999,1003,1111,1206,1238 'delay':7,347 'determinist':115,294,315 'direct':786 'disabl':1066 'document':83 'durabl':48,1296,1311 'durat':335 'e.g':13,821 'effect':275 'els':914 'elsewher':630 'email':364,378,704,953 'email/invoice.send':702 'emailid':986 'embrac':1315 'enabl':1204 'engag':370 'error':627 'event':28,156,195,404,425,431,440,455,460,472,494,548,565,569,573,593,652,689,745,748,1011,1014,1119,1122,1171,1176 'event.data.items':1127 'event.data.items.map':1020 'event.data.number':751,752 'event.data.remind':410 'event.data.userid':499 'everi':128,1168 'exact':654 'exampl':154,193 'execut':222,329,430,928,938,1162,1170 'expect':547 'export':148,187,1002,1110 'express':481,561,564,577 'expression-bas':480 'extern':27,39,808,1285 'externalfn':792,810 'fail':624 'fals':913,1080,1088 'fan':663 'fast':1057 'fast-servic':1056 'fetch':246,888,899 'fetch-pag':887,898 'fetch-us':245 'flow':544,1093 'fn':801,827,1086 'focus':72 'follow':20 'follow-up':19 'followup':376 'forget':320 'full':582 'fulli':772 'function':107,129,647,660,667,675,714,724,728,764,785,809,819,822,837,853,1009,1083,1159,1189,1196,1299,1310 'functionid':798 'gate':32 'get':762 'get-squar':761 'go':78 'good':192 'good-exampl':191 'gotcha':1158 'great':846 'group.parallel':1044,1051,1251 'guidanc':91 'handl':236,310,503,510,530,555,649,730,871,892,1228 'handle-timeout':509 'hasmor':881,884,912 'heavi':1008 'hello':203,205 'hour':15 'http':60,325,1200,1210 'human':24,540,1260 'human-in-the-loop':539,1259 'id':151,190,230,306,520,740,820,869,886,918,1005,1077,1085,1113,1221 'implement':6 'import':783,787,836 'independ':65 'index':1139,1144 'inngest':2,44,51,82,234,632,790,870,1076,1092,1227 'inngest-flow-control':1091 'inngest-step':1 'inngest.createfunction':150,189,739,1004,1112 'insid':122,296 'integr':1286 'invoc':778 'invoiceid':700,706 'invok':753 'item':1021,1026,1029 'job':1101 'key':812,1157 'languag':89,97 'language-specif':88 'larg':1116 'let':877,880 'level':1074,1084 'limit':127,905,1183 'llm':1297 'log':162,184,202 'log-hello':201 'logic':295,316,855 'longer':830 'loop':308,543,864,1226,1263 'lose':42 'make':1308 'map':860 'map-reduc':859 'match':476,479,483,522,575,598,640 'max':1184 'maximum':132 'maxruntim':1216 'mean':453 'method':54 'might':648 'monitor':68 'multi':1268 'multi-step':1267 'multipl':646,688,857 'must':9 'my-app-other-fn':823 'name':681,697,701 'need':278,718,1070 'never':124,456,513 'new':388,408,572,1075 'non':114,293 'non-determinist':113,292 'note':1241 'notif':283,696 'notifi':679 'notify-system':678 'notifyaccountingteam':516 'null':451,531,879 'number':767 'observ':1312 'onboard':1270 'onconflict':617 'oper':584 'optim':940,997,1035,1067,1236 'optimizeparallel':1079,1087 'option':1099 'orchestr':1298 'origin':567 'other-app':795 'other-fn':799 'output':1193 'outsid':125,165,1164 'overhead':1211 'overwrit':621 'page':889,895,900 'page.products':908,916 'page.products.length':910 'parallel':927,932,936,984,994,1007,1036,1068,1107,1132,1230,1234,1280 'parallel-heavy-funct':1006 'pattern':586,862,863 'paus':328,353 'pend':622 'per':1188,1191,1195 'perfect':733,1102 'platform':1214 'poll':38 'post':636 'pro':502 'process':11,922,1025,1105,1115,1129,1142,1279 'process-chunk':1141 'process-item':1024 'process-large-dataset':1114 'process-product':921 'process/batch':1012 'processallproduct':925 'processchunk':1145 'processdata':272 'processitem':1028 'product':560,923 'profilechang':687 'promis':1038,1247 'promise.all':930,990,1019,1136,1232 'promise.race':1030,1054,1243 'put':111,290,314 'python':76 'queri':120 'race':1041,1047,1254 'random':121 're':104,1161 're-execut':1160 're-run':103 'realtim':537,1265 'reason':528 'reduc':861,1209 'refer':79,579,838 'referencefunct':788,793,840 'reliabl':1289 'rememb':1306 'reminderd':387,402 'replac':618,620 'request':61,326,1201 'requestid':525 'requir':619 'resolv':1042 'restart':12 'result':242,273,671,720,732,750,756,803,1017,1134,1148,1153,1156 'retri':66 'retriabl':223 'return':254,257,271,277,298,452,515,532,749,902,924,955,966,977,1053,1154 'reus':233,304,854,867,890,1224 'review':31 'robust':47 'run':105,145,435,444,661,981,1166,1181,1197 'schedul':18,417 'scheduledtim':407,419 'sdk':635 'see':576,1090 'semant':1255 'send':282,361,375,628,952 'send-email':951 'send-followup':374 'send-notif':281 'send-welcom':360 'sendemail':286,363,949,991 'sendfollowupemail':377 'sendwelcomeemail':957 'sent':426,432,441,549,1177 'separ':59,324 'serverless':1213 'servic':40,1058,1063 'sessionid':524 'set':527 'settl':1039,1249 'shopify.products.list':903 'short':346 'short-delay':345 'side':274 'signal':591,605,613,623,629,639,657 'simpl':478 'skill':70 'skill-inngest-steps' 'sleep':380,1271 'slow':1062 'slow-servic':1061 'source-inngest' 'specif':90,383,659 'squar':743,758,763 'square.result':770 'st':43 'step':3,45,53,56,102,123,126,136,140,159,166,198,227,229,297,303,305,318,323,429,552,866,868,933,937,945,995,1015,1108,1123,1165,1169,1180,1182,1187,1192,1220,1235,1269,1273,1281,1307 'step.ai':1294 'step.invoke':725,760,805,833,1301 'step.run':169,174,179,200,207,212,217,221,244,267,280,359,373,508,897,920,950,961,972,1023,1055,1060,1140,1150,1287 'step.sendevent':662,677,693 'step.sleep':327,338,344,350,366 'step.sleepuntil':379,397,413 'step.waitforevent':420,467,489 'step.waitforsignal':587,607 'string':336,818 'subscript':487,493,975,988 'subscriptionservice.create':979 'subsequ':302 'support':831 'surviv':10 'synchron':260 'syntax':485,562,578,583 'system':680 't09':393 'task':602,611 'taskid':601,614,641 'test':157,196 'throttl':1098 'throw':625 'time':147,164,333,418,1172 'timeout':30,454,463,474,496,504,511,529,533,558,615 'topic-agent-skill-repository' 'topic-agent-skills' 'topic-agentic-skills' 'topic-ai-agents' 'topic-claude-code-skills' 'topic-cursor-skills' 'topic-openclaw-skills' 'total':139,1199 'transform':265,269 'transform-data':268 'trigger':155,194,568,673,712,744,1010,1089,1118 'true':882,1046,1253 'type':773 'typescript':74,142,238,334,385,458,599,672,736,874,943,1109 'ui':1266 'uniqu':519,590 'unnecessarili':319 'up':21 'updat':963 'update-crm':962 'updatecrm':960,992 'usag':240 'use':4,258,299,331,355,518,535,556,644,707,755,834,929,1043,1231,1250,1257 'user':247,250,255,969,1276 'user.email':287,705,958 'user.id':685,980 'user/profile.updated':682 'userid':253,523,684 'v4':815,935,1001,1033,1208,1240 'valu':813 'via':631 'wait':22,340,368,399,415,461,469,491,588,609,669,1244 'wait-24h':339 'wait-for-approv':468 'wait-for-christma':398 'wait-for-engag':367 'wait-for-scheduled-tim':414 'wait-for-subscript':490 'wait-for-task-complet':608 'waitforev':422,434,443,645,1173,1264,1274 'waitforsign':653 'want':710 'warn':814 'webhook':33 'week':352 'weekly-paus':351 'welcom':288,362 'winner':1049 'without':41,330,557,668,946 'work':262,1284 'workflow':49,357,850,858,1293,1305 'wrong':143 'www.inngest.com':85 'www.inngest.com/llms.txt)':84","prices":[{"id":"750fee01-5fe5-4889-a896-3592c47d7a91","listingId":"c705c280-1c1b-40da-b290-4ab0da12a38e","amountUsd":"0","unit":"free","nativeCurrency":null,"nativeAmount":null,"chain":null,"payTo":null,"paymentMethod":"skill-free","isPrimary":true,"details":{"org":"inngest","category":"inngest-skills","install_from":"skills.sh"},"createdAt":"2026-04-18T23:06:59.748Z"}],"sources":[{"listingId":"c705c280-1c1b-40da-b290-4ab0da12a38e","source":"github","sourceId":"inngest/inngest-skills/inngest-steps","sourceUrl":"https://github.com/inngest/inngest-skills/tree/main/skills/inngest-steps","isPrimary":false,"firstSeenAt":"2026-04-18T23:06:59.748Z","lastSeenAt":"2026-05-18T19:05:31.655Z"},{"listingId":"c705c280-1c1b-40da-b290-4ab0da12a38e","source":"skills_sh","sourceId":"inngest/inngest-skills/inngest-steps","sourceUrl":"https://skills.sh/inngest/inngest-skills/inngest-steps","isPrimary":true,"firstSeenAt":"2026-05-07T20:41:08.078Z","lastSeenAt":"2026-05-07T22:40:47.809Z"}],"details":{"listingId":"c705c280-1c1b-40da-b290-4ab0da12a38e","quickStartSnippet":null,"exampleRequest":null,"exampleResponse":null,"schema":null,"openapiUrl":null,"agentsTxtUrl":null,"citations":[],"useCases":[],"bestFor":[],"notFor":[],"kindDetails":{"org":"inngest","slug":"inngest-steps","github":{"repo":"inngest/inngest-skills","stars":22,"topics":["agent-skill-repository","agent-skills","agentic-skills","ai-agents","claude-code-skills","cursor-skills","openclaw-skills"],"license":"other","html_url":"https://github.com/inngest/inngest-skills","pushed_at":"2026-05-06T18:21:48Z","description":"Agent Skills for building with Inngest","skill_md_sha":"c835cb965e5f6b2cabb4c50d1e68b934344fc0b4","skill_md_path":"skills/inngest-steps/SKILL.md","default_branch":"main","skill_tree_url":"https://github.com/inngest/inngest-skills/tree/main/skills/inngest-steps"},"layout":"multi","source":"github","category":"inngest-skills","frontmatter":{"name":"inngest-steps","description":"Use when implementing delays that must survive process restarts (e.g., 24-hour cart abandonment, scheduled follow-ups), waiting for human approval or external events with timeouts (review gates, webhook callbacks, async API completion), polling external services without losing state on crashes, calling other functions and awaiting their results, memoizing expensive operations so they don't re-run on retry, or running async work in parallel inside a workflow. Covers Inngest step methods: step.run, step.sleep, step.waitForEvent, step.waitForSignal, step.sendEvent, step.invoke, step.ai, plus patterns for loops and parallel execution."},"skills_sh_url":"https://skills.sh/inngest/inngest-skills/inngest-steps"},"updatedAt":"2026-05-18T19:05:31.655Z"}}