$npx -y skills add vercel/workflow --skill migrating-to-workflow-sdkMigrates Temporal, Inngest, Trigger.dev, and AWS Step Functions workflows to the Workflow SDK. Use when porting Activities, Workers, Signals, step.run(), step.waitForEvent(), Trigger.dev tasks / wait.forToken / triggerAndWait, ASL JSON state machines, Task/Choice/Wait/Parallel st
| 1 | # Migrating to the Workflow SDK |
| 2 | |
| 3 | Use this skill when converting an existing orchestration system to the Workflow SDK. |
| 4 | |
| 5 | ## Intake |
| 6 | |
| 7 | 1. Identify the source system: |
| 8 | - Temporal |
| 9 | - Inngest |
| 10 | - Trigger.dev |
| 11 | - AWS Step Functions |
| 12 | 2. Identify the target runtime: |
| 13 | - Managed hosting -> keep examples focused on `start()`, `getRun()`, hooks/webhooks, and route handlers. |
| 14 | - Self-hosted -> also read `references/runtime-targets.md` and explicitly say the workflow/step code can stay the same, but deployment still needs a `World` implementation and startup bootstrap. |
| 15 | 3. Extract the source constructs: |
| 16 | - entrypoint |
| 17 | - waits / timers |
| 18 | - external callbacks / approvals |
| 19 | - retries / failure handling |
| 20 | - child workflows / fan-out |
| 21 | - progress streaming |
| 22 | - external side effects |
| 23 | |
| 24 | ## Default migration rules |
| 25 | |
| 26 | - Put orchestration in `"use workflow"` functions. |
| 27 | - Put side effects, SDK calls, DB calls, HTTP calls, and stream I/O in `"use step"` functions. |
| 28 | - Use `sleep()` only in workflow context. |
| 29 | - For Signals, `step.waitForEvent()`, and `.waitForTaskToken`, choose exactly one resume surface: |
| 30 | - `resume/internal` -> `createHook()` + `resumeHook()` when the app resumes from server-side code with a deterministic business token. |
| 31 | - `resume/url/default` -> `createWebhook()` when the external system needs a generated callback URL and the default `202 Accepted` response is fine. |
| 32 | - `resume/url/manual` -> `createWebhook({ respondWith: 'manual' })` only when the prompt explicitly requires a custom response body, status, or headers. |
| 33 | - If a callback-URL prompt does not specify response semantics, default to `resume/url/default` and make the assumption explicit in `## Open Questions`. |
| 34 | - Never pair `createWebhook()` with `resumeHook()`, and never pass `token:` to `createWebhook()`. |
| 35 | - Wrap `start()` and `getRun()` inside `"use step"` functions for child runs. |
| 36 | - Use `getStepMetadata().stepId` as the idempotency key for external writes. |
| 37 | - Use `getWritable()` in workflow context to obtain the stream, but interact with it (write, close) only inside `"use step"` functions. |
| 38 | - Prefer rollback stacks for multi-step compensation. |
| 39 | - Choose app-boundary syntax in this order: |
| 40 | 1. If the prompt explicitly asks for framework-agnostic app-boundary code, use plain `Request` / `Response` even when a framework like Hono is named. |
| 41 | 2. Otherwise, if the target framework is named, shape app-boundary examples to that framework. |
| 42 | 3. Otherwise, keep examples framework-agnostic with `Request` / `Response`. Do not default to Next.js-only route signatures unless Next.js is explicitly named. |
| 43 | |
| 44 | > Fast memory aid: |
| 45 | > - Callback URL + default ack -> `createWebhook()` |
| 46 | > - Callback URL + custom ack -> `createWebhook({ respondWith: 'manual' })` |
| 47 | > - Deterministic server-side resume -> `createHook()` + `resumeHook()` |
| 48 | |
| 49 | ## Fast-path router |
| 50 | |
| 51 | Load `references/resume-routing.md` when the source pauses for Signals, `step.waitForEvent()`, or `.waitForTaskToken`. |
| 52 | |
| 53 | Fast defaults: |
| 54 | |
| 55 | - callback URL only -> `resume/url/default` |
| 56 | - callback URL + explicit custom response -> `resume/url/manual` |
| 57 | - deterministic server-side resume -> `resume/internal` |
| 58 | - self-hosted -> add `runtime/self-hosted` |
| 59 | - named framework -> add `boundary/named-framework` |
| 60 | - explicit framework-agnostic request -> add `boundary/framework-agnostic` |
| 61 | |
| 62 | Before drafting `## Migrated Code`, write the selected route keys in `## Migration Plan`. |
| 63 | |
| 64 | ## Source references |
| 65 | |
| 66 | - Temporal -> `references/temporal.md` |
| 67 | - Inngest -> `references/inngest.md` |
| 68 | - Trigger.dev -> `references/trigger-dev.md` |
| 69 | - AWS Step Functions -> `references/aws-step-functions.md` |
| 70 | |
| 71 | ## Shared references |
| 72 | |
| 73 | - `references/shared-patterns.md` — reusable code templates for hooks, child workflows, idempotency, streaming, and rollback. |
| 74 | - `references/runtime-targets.md` — Managed vs custom `World` guidance. |
| 75 | - `references/resume-routing.md` — route-key selection, obligations, and exact `## Migration Plan` shape. |
| 76 | - `references/retries.md` — canonical retry mechanics: `stepFn.maxRetries`, `RetryableError({ retryAfter })`, `FatalError`. |
| 77 | |
| 78 | ## Required output shape |
| 79 | |
| 80 | Return the migration in this structure: |
| 81 | |
| 82 | ```md |
| 83 | ## Migration Plan |
| 84 | ## Source -> Target Mapping |
| 85 | ## Migrated Code |
| 86 | ## App Boundary / Resume Endpoints |
| 87 | ## Verification Checklist |
| 88 | ## Open Questions |
| 89 | ``` |
| 90 | |
| 91 | ## Verification checklist |
| 92 | |
| 93 | Fail the draft if any of these are true: |
| 94 | |
| 95 | - [ ] `## Migration Plan` omits `Route keys` |
| 96 | - [ ] `## Migration Plan` omits `Why these route keys` |
| 97 | - [ ] `## Migration Plan` lists route keys that do not match the prompt |
| 98 | - [ ] `## Migration Plan` lists required code obligations |