{"id":"c705c280-1c1b-40da-b290-4ab0da12a38e","shortId":"GR2Ew2","kind":"skill","title":"inngest-steps","tagline":"Use Inngest step methods to build durable workflows. Covers step.run, step.sleep, step.waitForEvent, step.waitForSignal, step.sendEvent, step.invoke, step.ai, and patterns for loops and parallel execution.","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.458","qualityRationale":"deterministic score 0.46 from registry signals: · indexed on github topic:agent-skills · 17 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-04-23T01:02:09.342Z","embedding":null,"createdAt":"2026-04-18T23:06:59.748Z","updatedAt":"2026-04-23T01:02:09.342Z","lastSeenAt":"2026-04-23T01:02:09.342Z","tsv":"'-12':374 '-25':375 '/llms.txt)':69 '/references/expressions.md':563 '/v1/events':620 '00':377 '000':118,1169 '00z':378 '1':117,579,580,638,639,1168 '10':1111 '16':754 '1h':599 '2024':373 '24h':324,325 '30d':480 '30s':331 '32mb':1177 '3d':354 '4':129,146,751 '49':900 '4mb':121,1173 '50':889,894 '7d':337,458 'across':78,839 'action':1260 'aggregateresult':1138 'ai':1275 'allproduct':859,909 'allproducts.push':890 'alway':239,431,509 'api':100,616,1273 'app':760,780,808,827,1061 'app/invoice.approved':456 'app/subscription.created':478 'appid':777 'appli':77 'approv':448,454,489,495 'arriv':440 'async':141,180,231,267,553,730,884,937,948,959,996,1035,1104 'async.data.plan':484 'async.data.userid':483 'automat':218,294,856,876 'await':151,156,161,182,189,194,199,226,234,249,262,268,320,326,332,341,348,355,379,395,449,471,490,589,659,675,742,787,879,902,930,939,950,961,972,1001,1033,1118,1132 'b':158,160,196,198 'bad':136,150 'bad-exampl':135 'base':465 'basic':222,442 'batch':678,1087 'batch-notif':677 'begin':93 'behavior':1014 'better':577 'billing/invoice.created':681 'break':799,831 'build':9,29,1286 'c':163,165,201,203 'calculate/square':729 'call':101,709,790,828,1274 'call-extern':789 'callfastservic':1042 'callslowservic':1047 'came':497 'case':517,1241 'catch':407,1158 'caught':422,430 'cel':467 'chang':669,800 'check':432 'checkpoint':1185 'christma':384 'chunk':1083,1108,1113,1121,1126,1129,1266 'chunkarray':1109 'chunks.map':1120 'client':1056,1202 'code':99,207,244,1146 'combin':1130,1135 'combine-result':1134 'common':1239 'complet':595 'complex':832,1287 'compos':835 'composit':718,1283 'comput':315,725 'compute-squar':724 'computesquar':721,748 'concept':76,82 'concurr':1079 'configur':1198 'console.log':143,154,159,164,187,192,197,202,752 'const':224,232,247,369,389,447,469,583,587,720,740,774,785,858,877,931,942,953,968,999,1031,1107,1116 'control':1077 'core':75,81 'correct':166 'counter':220,292,855,874,1212 'cover':12 'creat':927,957 'create-subscript':956 'createsubscript':954,976 'critic':83,404 'crm':947 'crmrecord':970 'crmservice.adduser':951 'cross':759,826 'cross-app':758,825 'crypto.randomuuid':586 'current':706 'cursor':861,887,898 'data':124,242,253,283,388,666,682,686,749,794,1261 'data.invoiceid':460 'data/process.large':1103 'dataset':1100 'date':372,392 'datetim':367 'db':102 'db.user.findbyid':235 'debugg':1297 'default':132,171,925,982,986,1094,1189,1221 'delay':330 'determinist':98,277,298 'direct':769 'disabl':1049 'document':66 'durabl':10,31,1279,1294 'durat':318 'e.g':804 'effect':258 'els':897 'elsewher':613 'email':347,361,687,936 'email/invoice.send':685 'emailid':969 'embrac':1298 'enabl':1187 'engag':353 'error':610 'event':139,178,387,408,414,423,438,443,455,477,531,548,552,556,576,635,672,728,731,994,997,1102,1105,1154,1159 'event.data.items':1110 'event.data.items.map':1003 'event.data.number':734,735 'event.data.remind':393 'event.data.userid':482 'everi':111,1151 'exact':637 'exampl':137,176 'execut':26,205,312,413,911,921,1145,1153 'expect':530 'export':131,170,985,1093 'express':464,544,547,560 'expression-bas':463 'extern':791,1268 'externalfn':775,793 'fail':607 'fals':896,1063,1071 'fan':646 'fast':1040 'fast-servic':1039 'fetch':229,871,882 'fetch-pag':870,881 'fetch-us':228 'flow':527,1076 'fn':784,810,1069 'focus':55 'followup':359 'forget':303 'full':565 'fulli':755 'function':90,112,630,643,650,658,697,707,711,747,768,792,802,805,820,836,992,1066,1142,1172,1179,1282,1293 'functionid':781 'get':745 'get-squar':744 'go':61 'good':175 'good-exampl':174 'gotcha':1141 'great':829 'group.parallel':1027,1034,1234 'guidanc':74 'handl':219,293,486,493,513,538,632,713,854,875,1211 'handle-timeout':492 'hasmor':864,867,895 'heavi':991 'hello':186,188 'http':43,308,1183,1193 'human':523,1243 'human-in-the-loop':522,1242 'id':134,173,213,289,503,723,803,852,869,901,988,1060,1068,1096,1204 'import':766,770,819 'independ':48 'index':1122,1127 'inngest':2,5,27,34,65,217,615,773,853,1059,1075,1210 'inngest-flow-control':1074 'inngest-step':1 'inngest.createfunction':133,172,722,987,1095 'insid':105,279 'integr':1269 'invoc':761 'invoiceid':683,689 'invok':736 'item':1004,1009,1012 'job':1084 'key':795,1140 'languag':72,80 'language-specif':71 'larg':1099 'let':860,863 'level':1057,1067 'limit':110,888,1166 'llm':1280 'log':145,167,185 'log-hello':184 'logic':278,299,838 'longer':813 'loop':23,291,526,847,1209,1246 'make':1291 'map':843 'map-reduc':842 'match':459,462,466,505,558,581,623 'max':1167 'maximum':115 'maxruntim':1199 'mean':436 'method':7,37 'might':631 'monitor':51 'multi':1251 'multi-step':1250 'multipl':629,671,840 'my-app-other-fn':806 'name':664,680,684 'need':261,701,1053 'never':107,439,496 'new':371,391,555,1058 'non':97,276 'non-determinist':96,275 'note':1224 'notif':266,679 'notifi':662 'notify-system':661 'notifyaccountingteam':499 'null':434,514,862 'number':750 'observ':1295 'onboard':1253 'onconflict':600 'oper':567 'optim':923,980,1018,1050,1219 'optimizeparallel':1062,1070 'option':1082 'orchestr':1281 'origin':550 'other-app':778 'other-fn':782 'output':1176 'outsid':108,148,1147 'overhead':1194 'overwrit':604 'page':872,878,883 'page.products':891,899 'page.products.length':893 'parallel':25,910,915,919,967,977,990,1019,1051,1090,1115,1213,1217,1263 'parallel-heavy-funct':989 'pattern':21,569,845,846 'paus':311,336 'pend':605 'per':1171,1174,1178 'perfect':716,1085 'platform':1197 'post':619 'pro':485 'process':905,1008,1088,1098,1112,1125,1262 'process-chunk':1124 'process-item':1007 'process-large-dataset':1097 'process-product':904 'process/batch':995 'processallproduct':908 'processchunk':1128 'processdata':255 'processitem':1011 'product':543,906 'profilechang':670 'promis':1021,1230 'promise.all':913,973,1002,1119,1215 'promise.race':1013,1037,1226 'put':94,273,297 'python':59 'queri':103 'race':1024,1030,1237 'random':104 're':87,1144 're-execut':1143 're-run':86 'realtim':520,1248 'reason':511 'reduc':844,1192 'refer':62,562,821 'referencefunct':771,776,823 'reliabl':1272 'rememb':1289 'reminderd':370,385 'replac':601,603 'request':44,309,1184 'requestid':508 'requir':602 'resolv':1025 'result':225,256,654,703,715,733,739,786,1000,1117,1131,1136,1139 'retri':49 'retriabl':206 'return':237,240,254,260,281,435,498,515,732,885,907,938,949,960,1036,1137 'reus':216,287,837,850,873,1207 'robust':30 'run':88,128,418,427,644,964,1149,1164,1180 'schedul':400 'scheduledtim':390,402 'sdk':618 'see':559,1073 'semant':1238 'send':265,344,358,611,935 'send-email':934 'send-followup':357 'send-notif':264 'send-welcom':343 'sendemail':269,346,932,974 'sendfollowupemail':360 'sendwelcomeemail':940 'sent':409,415,424,532,1160 'separ':42,307 'serverless':1196 'servic':1041,1046 'sessionid':507 'set':510 'settl':1022,1232 'shopify.products.list':886 'short':329 'short-delay':328 'side':257 'signal':574,588,596,606,612,622,640 'simpl':461 'skill':53 'skill-inngest-steps' 'sleep':363,1254 'slow':1045 'slow-servic':1044 'source-inngest' 'specif':73,366,642 'squar':726,741,746 'square.result':753 'step':3,6,28,36,39,85,106,109,119,123,142,149,181,210,212,280,286,288,301,306,412,535,849,851,916,920,928,978,998,1091,1106,1148,1152,1163,1165,1170,1175,1203,1218,1252,1256,1264,1290 'step.ai':19,1277 'step.invoke':18,708,743,788,816,1284 'step.run':13,152,157,162,183,190,195,200,204,227,250,263,342,356,491,880,903,933,944,955,1006,1038,1043,1123,1133,1270 'step.sendevent':17,645,660,676 'step.sleep':14,310,321,327,333,349 'step.sleepuntil':362,380,396 'step.waitforevent':15,403,450,472 'step.waitforsignal':16,570,590 'string':319,801 'subscript':470,476,958,971 'subscriptionservice.create':962 'subsequ':285 'support':814 'synchron':243 'syntax':468,545,561,566 'system':663 't09':376 'task':585,594 'taskid':584,597,624 'test':140,179 'throttl':1081 'throw':608 'time':130,147,316,401,1155 'timeout':437,446,457,479,487,494,512,516,541,598 'topic-agent-skill-repository' 'topic-agent-skills' 'topic-agentic-skills' 'topic-ai-agents' 'topic-claude-code-skills' 'topic-cursor-skills' 'topic-openclaw-skills' 'total':122,1182 'transform':248,252 'transform-data':251 'trigger':138,177,551,656,695,727,993,1072,1101 'true':865,1029,1236 'type':756 'typescript':57,125,221,317,368,441,582,655,719,857,926,1092 'ui':1249 'uniqu':502,573 'unnecessarili':302 'updat':946 'update-crm':945 'updatecrm':943,975 'usag':223 'use':4,241,282,314,338,501,518,539,627,690,738,817,912,1026,1214,1233,1240 'user':230,233,238,952,1259 'user.email':270,688,941 'user.id':668,963 'user/profile.updated':665 'userid':236,506,667 'v4':798,918,984,1016,1191,1223 'valu':796 'via':614 'wait':323,351,382,398,444,452,474,571,592,652,1227 'wait-24h':322 'wait-for-approv':451 'wait-for-christma':381 'wait-for-engag':350 'wait-for-scheduled-tim':397 'wait-for-subscript':473 'wait-for-task-complet':591 'waitforev':405,417,426,628,1156,1247,1257 'waitforsign':636 'want':693 'warn':797 'week':335 'weekly-paus':334 'welcom':271,345 'winner':1032 'without':313,540,651,929 'work':245,1267 'workflow':11,32,340,833,841,1276,1288 'wrong':126 'www.inngest.com':68 'www.inngest.com/llms.txt)':67","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-04-23T01:02:09.342Z"}],"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":17,"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-04-20T23:35:15Z","description":"Agent Skills for building with Inngest","skill_md_sha":"5180ee6b9c84dcc979bac819c64a1447b2bef89f","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 Inngest step methods to build durable workflows. Covers step.run, step.sleep, step.waitForEvent, step.waitForSignal, step.sendEvent, step.invoke, step.ai, and patterns for loops and parallel execution."},"skills_sh_url":"https://skills.sh/inngest/inngest-skills/inngest-steps"},"updatedAt":"2026-04-23T01:02:09.342Z"}}