migrating-to-workflow-sdk — Claude Code skill: port workflows
Ports orchestration from Temporal, Inngest, Trigger.dev or AWS Step Functions to the Workflow SDK, returning a migration plan and rewritten code.
npx skills add vercel/workflow --skill migrating-to-workflow-sdk -a claude-codeWhat migrating-to-workflow-sdk does
The skill kicks in when you move an existing orchestration system onto the Workflow SDK. It first pins down the source system and the target runtime, then extracts entrypoints, waits and timers, external callbacks, retries, child workflows and side effects from the old code.
From there it follows hard rules. Orchestration goes into "use workflow" functions; SDK calls, database and HTTP calls, and stream I/O go into "use step" functions. For signals and .waitForTaskToken you pick exactly one resume surface: createHook() plus resumeHook() for a deterministic server-side resume, or createWebhook() when an external system needs a generated callback URL. Pairing createWebhook() with resumeHook() fails the draft.
Output has a fixed shape: migration plan, source-to-target mapping, migrated code, app boundary, verification checklist and open questions. The checklist rejects a draft when source-framework primitives survive, when sleep() lands inside a step, or when a child workflow calls start() straight from workflow context. For self-hosted targets the skill also reads references/runtime-targets.md — step code stays the same, but deployment still needs a World implementation and startup bootstrap.
What it helps with
- move Activities and Workers off Temporal
- rewrite Inngest
step.run()andstep.waitForEvent() - replace Trigger.dev
wait.forTokenandtriggerAndWait - translate ASL JSON with Task, Choice, Wait and Parallel states
- pull side effects out of workflow context into steps
Example prompts for the agent
- Port my Temporal workflow to the Workflow SDK and show the migration plan with the verification checklist
- I have Inngest with
step.waitForEvent()and need a callback URL with a plain 202 response — pick the resume surface - Convert my AWS Step Functions ASL machine, Task and Choice states, to
"use workflow"and"use step"
How to install migrating-to-workflow-sdk
1Skills CLI (Vercel)
npx skills add vercel/workflow --skill migrating-to-workflow-sdk -a claude-code2Manually: put the files in place
~/.claude/skills/migrating-to-workflow-sdk/SKILL.mdCopy the whole skill folder; for one project use .claude/skills/migrating-to-workflow-sdk/
1Skills CLI (Vercel)
npx skills add vercel/workflow --skill migrating-to-workflow-sdk -a codex2Manually: put the files in place
.agents/skills/migrating-to-workflow-sdk/SKILL.mdFor all projects use ~/.agents/skills/
1Skills CLI (Vercel)
npx skills add vercel/workflow --skill migrating-to-workflow-sdk -a cursor2Manually: put the files in place
.cursor/skills/migrating-to-workflow-sdk/SKILL.mdCursor also reads .agents/skills/ and .claude/skills/
1GitHub CLI
gh skill install vercel/workflow migrating-to-workflow-sdk2Manually: put the files in place
.github/skills/migrating-to-workflow-sdk/SKILL.md1Skills CLI (Vercel)
npx skills add vercel/workflow --skill migrating-to-workflow-sdk -a gemini-cli2Platform CLI
gemini skills install https://github.com/vercel/workflow --path skills/migrating-to-workflow-sdkManually: put the files in place
.devin/skills/migrating-to-workflow-sdk/SKILL.mdThe legacy .windsurf/skills/ path still works
Skills CLI (Vercel)
npx skills add vercel/workflow --skill migrating-to-workflow-sdk -a opencodeClaude.ai
Zip the folder and upload it in Settings → Capabilities → Skills
Step by step, with commands for each platform: How to install skills in Claude Code: five ways
Questions about migrating-to-workflow-sdk
How do I install migrating-to-workflow-sdk in Claude?
Run npx skills add vercel/workflow --skill migrating-to-workflow-sdk -a claude-code. The skill lands in ~/.claude/skills/migrating-to-workflow-sdk/SKILL.md.
What does migrating-to-workflow-sdk do?
It reads your existing orchestration and ports it to the Workflow SDK: identifies the source system, picks a resume surface, and returns a migration plan with code and a verification checklist.
Which systems can it migrate from?
Temporal, Inngest, Trigger.dev and AWS Step Functions. Each one has its own file under references/.
Source text
SKILL.md · Apache-2.0
---
name: migrating-to-workflow-sdk
description: Migrates 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 states, task tokens, or child workflows.
metadata:
author: Vercel Inc.
version: '0.3.0'
---
# Migrating to the Workflow SDK
Use this skill when converting an existing orchestration system to the Workflow SDK.
## Intake
1. Identify the source system:
- Temporal
- Inngest
- Trigger.dev
- AWS Step Functions
2. Identify the target runtime:
- Managed hosting -> keep examples focused on `start()`, `getRun()`, hooks/webhooks, and route handlers.
- 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.
3. Extract the source constructs:
- entrypoint
- waits / timers
- external callbacks / approvals
- retries / failure handling
- child workflows / fan-out
- progress streaming
- external side effects
## Default migration rules
- Put orchestration in `"use workflow"` functions.
- Put side effects, SDK calls, DB calls, HTTP calls, and stream I/O in `"use step"` functions.
- Use `sleep()` only in workflow context.
- For Signals, `step.waitForEvent()`, and `.waitForTaskToken`, choose exactly one resume surface:
- `resume/internal` -> `createHook()` + `resumeHook()` when the app resumes from server-side code with a deterministic business token.
- `resume/url/default` -> `createWebhook()` when the external system needs a generated callback URL and the default `202 Accepted` response is fine.
- `resume/url/manual` -> `createWebhook({ respondWith: 'manual' })` only when the prompt explicitly requires a custom response body, status, or headers.
- If a callback-URL prompt does not specify response semantics, default to `resume/url/default` and make the assumption explicit in `## Open Questions`.
- Never pair `createWebhook()` with `resumeHook()`, and never pass `token:` to `createWebhook()`.
- Wrap `start()` and `getRun()` inside `"use step"` functions for child runs.
- Use `getStepMetadata().stepId` as the idempotency key for external writes.
- Use `getWritable()` in workflow context to obtain the stream, but interact with it (write, close) only inside `"use step"` functions.
- Prefer rollback stacks for multi-step compensation.
- Choose app-boundary syntax in this order:
1. If the prompt explicitly asks for framework-agnostic app-boundary code, use plain `Request` / `Response` even when a framework like Hono is named.
2. Otherwise, if the target framework is named, shape app-boundary examples to that framework.
3. Otherwise, keep examples framework-agnostic with `Request` / `Response`. Do not default to Next.js-only route signatures unless Next.js is explicitly named.
> Fast memory aid:
> - Callback URL + default ack -> `createWebhook()`
> - Callback URL + custom ack -> `createWebhook({ respondWith: 'manual' })`
> - Deterministic server-side resume -> `createHook()` + `resumeHook()`
## Fast-path router
Load `references/resume-routing.md` when the source pauses for Signals, `step.waitForEvent()`, or `.waitForTaskToken`.
Fast defaults:
- callback URL only -> `resume/url/default`
- callback URL + explicit custom response -> `resume/url/manual`
- deterministic server-side resume -> `resume/internal`
- self-hosted -> add `runtime/self-hosted`
- named framework -> add `boundary/named-framework`
- explicit framework-agnostic request -> add `boundary/framework-agnostic`
Before drafting `## Migrated Code`, write the selected route keys in `## Migration Plan`.
## Source references
- Temporal -> `references/temporal.md`
- Inngest -> `references/inngest.md`
- Trigger.dev -> `references/trigger-dev.md`
- AWS Step Functions -> `references/aws-step-functions.md`
## Shared references
- `references/shared-patterns.md`: Reusable code templates for hooks, child workflows, idempotency, streaming, and rollback.
- `references/runtime-targets.md`: Managed vs. custom `World` guidance.
- `references/resume-routing.md`: Route-key selection, obligations, and exact `## Migration Plan` shape.
- `references/retries.md`: Canonical retry mechanics, including `stepFn.maxRetries`, `RetryableError({ retryAfter })`, and `FatalError`.
## Required output shape
Return the migration in this structure:
```md
## Migration Plan
## Source -> Target Mapping
## Migrated Code
## App Boundary / Resume Endpoints
## Verification Checklist
## Open Questions
```
## Verification checklist
Fail the draft if any of these are true:
- [ ] `## Migration Plan` omits `Route keys`
- [ ] `## Migration Plan` omits `Why these route keys`
- [ ] `## Migration Plan` lists route keys that do not match the prompt
- [ ] `## Migration Plan` lists required code obligations that do not match the selected route keys
- [ ] Source-framework primitives remain in the migrated code
- [ ] Side effects remain in workflow context
- [ ] `sleep()` appears inside a step
- [ ] Stream interaction (`getWriter()`, `write()`, `close()`) appears inside a workflow function
- [ ] Child workflows call `start()` / `getRun()` directly from workflow context
- [ ] External writes omit idempotency keys
- [ ] Hooks/webhooks are missing where the source used signals, waitForEvent, or task tokens
- [ ] A callback-URL flow uses `createHook()` + `resumeHook()` instead of `createWebhook()`
- [ ] A `resume/url/default` or `resume/url/manual` migration invents a user-authored callback route or `resumeWebhook()` wrapper when `webhook.url` should be the only resume surface
- [ ] `createWebhook()` is given a custom `token` or paired with `resumeHook()`
Validation note:
- Reading webhook request data in workflow context is allowed. Only `request.respondWith()` is step-only.
Additional fail conditions:
- `resume/internal` output omits `resumeHook()` in app-boundary code
- `resume/internal` output omits a deterministic business token
- `resume/internal` output emits `createWebhook()` or `webhook.url`
- `resume/url/default` output does not pass `webhook.url` to the external system
- `resume/url/default` output emits `resumeHook()`, `respondWith: 'manual'`, or `RequestWithResponse` without a custom-response requirement in the prompt
- `resume/url/default` output invents a user-authored callback route or `resumeWebhook()` wrapper when `webhook.url` is the intended resume surface
- `resume/url/manual` output does not pass `webhook.url` to the external system
- `resume/url/manual` output omits `RequestWithResponse` or `await request.respondWith(...)`
- `resume/url/manual` output calls `request.respondWith(...)` outside a `"use step"` function
- `resume/url/manual` output invents a user-authored callback route or `resumeWebhook()` wrapper when `webhook.url` is the intended resume surface
- `createWebhook()` is paired with `resumeHook()`
- self-hosted output omits `World extends Queue, Streamer, Storage`, `startWorkflowWorld()`, or the explicit note that the workflow and step code can stay the same while the app still needs a custom `World`
- named-framework output mixes framework syntax with plain `Request` / `Response` app-boundary code without a framework-agnostic override
For concrete passing code, load:
- `references/shared-patterns.md` -> `## Generated callback URL (default response)`
- `references/shared-patterns.md` -> `## Generated callback URL (manual response)`
- `references/runtime-targets.md` -> `## Self-hosted output block`
- `references/aws-step-functions.md` -> `## Combined recipe: callback URL on self-hosted Hono`
## Sample prompt
```text
Migrate this Inngest workflow to the Workflow SDK.
It uses step.waitForEvent() with a timeout and step.realtime.publish().
```
Expected response shape:
```md
## Migration Plan
## Source -> Target Mapping
## Migrated Code
## App Boundary / Resume Endpoints
## Verification Checklist
## Open Questions
```
## Example references
Load a worked example only when the prompt needs concrete code:
- `references/shared-patterns.md` -> `## Named-framework internal resume example (Hono)`
- `references/shared-patterns.md` -> `## Generated callback URL (default response)`
- `references/shared-patterns.md` -> `## Generated callback URL (manual response)`
- `references/runtime-targets.md` -> `## Self-hosted output block`
- `references/aws-step-functions.md` -> `## Combined recipe: callback URL on self-hosted Hono`
Reject these counterexamples:
- `resume/url/default` or `resume/url/manual` + user-authored callback route when `webhook.url` is the intended resume surface
- `createWebhook()` paired with `resumeHook()`
- named-framework app-boundary output mixed with plain `Request` / `Response` without a framework-agnostic override
© Vercel Inc. · Apache-2.0 · vercel/workflow