workflows
Durable, long-running workflows with automatic retries and state persistence. Load when building multi-step async processes, implementing human-in-the-loop approval flows, coordinating API calls with retry logic, or creating reliable background jobs that survive restarts.
What this skill does
# Cloudflare Workflows
Build durable, long-running workflows that survive restarts and handle retries automatically using Cloudflare Workflows.
## When to Use
Workflows are ideal for:
- **Multi-step async tasks** - Break complex processes into retriable steps
- **Human-in-the-loop workflows** - Pause execution waiting for external input
- **Reliable background jobs** - Automatic retries with exponential backoff
- **Long-running processes** - Minutes to hours of execution with state persistence
- **Coordinated API calls** - Chain multiple API calls with retry logic
**Don't use Workflows for**:
- Simple request/response handlers (use Workers)
- Real-time operations requiring <100ms response (use Workers)
- Tasks that complete in <1 second (use Workers directly)
## Quick Reference
| Operation | API |
|-----------|-----|
| Define workflow | `class MyWorkflow extends WorkflowEntrypoint<Env, Params>` |
| Execute step | `await step.do('name', async () => { ... })` |
| Sleep/pause | `await step.sleep('wait', '1 minute')` |
| Step with retries | `await step.do('name', { retries: { limit: 5 } }, async () => {})` |
| Create instance | `await env.MY_WORKFLOW.create({ id, params })` |
| Get instance | `await env.MY_WORKFLOW.get(id)` |
| Check status | `await instance.status()` |
## FIRST: wrangler.jsonc Configuration
Add workflow binding to your configuration:
```jsonc
{
"name": "my-project",
"main": "src/index.ts",
"compatibility_date": "2025-02-11",
"workflows": [
{
"name": "workflows-starter",
"binding": "MY_WORKFLOW",
"class_name": "MyWorkflow"
}
]
}
```
**Key points**:
- `binding` - Environment variable name to access workflow
- `class_name` - Must match your exported Workflow class name exactly
- Multiple workflows can be defined in the array
## Critical Limits to Know
**Per-Step State Limit: 1 MiB**
- Each step's return value must be under 1 MiB (1,048,576 bytes)
- If exceeded, the step fails
- **Workaround**: Store large data in R2/KV and return a reference
```typescript
// ✅ Good: Store large data externally
const dataRef = await step.do('process large file', async () => {
const response = await fetch('https://api.example.com/large-dataset');
const data = await response.text();
const key = crypto.randomUUID();
await this.env.BUCKET.put(key, data); // Store in R2
return { key }; // Small reference (<1 KiB)
});
```
**Total Instance State**: 100 MB (Free) / 1 GB (Paid)
- Sum of all step return values across the workflow
**Concurrency**: Only `running` instances count toward limits
- `waiting` instances (sleeping, retrying, waiting for events) do NOT count
- You can have millions sleeping simultaneously
See [references/limits.md](references/limits.md) for complete limits documentation.
## Basic Workflow Example
```typescript
import { WorkflowEntrypoint, WorkflowStep, WorkflowEvent } from 'cloudflare:workers';
type Env = {
MY_WORKFLOW: Workflow;
// Add your bindings here (KV, D1, R2, etc.)
};
// User-defined params passed to your workflow
type Params = {
email: string;
metadata: Record<string, string>;
};
export class MyWorkflow extends WorkflowEntrypoint<Env, Params> {
async run(event: WorkflowEvent<Params>, step: WorkflowStep) {
// Access bindings via this.env
// Access params via event.payload
const files = await step.do('fetch files', async () => {
// This step's result is persisted
return {
files: [
'doc_7392_rev3.pdf',
'report_x29_final.pdf',
'memo_2024_05_12.pdf',
],
};
});
// Access previous step results
const apiResponse = await step.do('call api', async () => {
let resp = await fetch('https://api.cloudflare.com/client/v4/ips');
return await resp.json<any>();
});
// Pause execution for a duration
await step.sleep('wait on something', '1 minute');
// Step with retry and timeout configuration
await step.do(
'write to storage',
{
retries: {
limit: 5,
delay: '5 second',
backoff: 'exponential',
},
timeout: '15 minutes',
},
async () => {
// Use results from previous steps
console.log('Files from step 1:', files.files.length);
if (Math.random() > 0.5) {
throw new Error('Simulated failure - will retry');
}
},
);
}
}
export default {
async fetch(req: Request, env: Env): Promise<Response> {
let url = new URL(req.url);
if (url.pathname.startsWith('/favicon')) {
return Response.json({}, { status: 404 });
}
// Get status of existing instance
let id = url.searchParams.get('instanceId');
if (id) {
let instance = await env.MY_WORKFLOW.get(id);
return Response.json({
status: await instance.status(),
});
}
const data = await req.json();
// Create new workflow instance
let instance = await env.MY_WORKFLOW.create({
id: crypto.randomUUID(),
params: data, // Available on WorkflowEvent in run()
});
return Response.json({
id: instance.id,
details: await instance.status(),
});
},
};
```
## Critical Rules for Workflows
Before diving into patterns, understand these essential rules (see [references/rules.md](references/rules.md) for details):
1. **Always `await` steps** - Forgetting `await` causes lost state and swallowed errors
2. **Don't store state outside steps** - In-memory variables are lost on hibernation; only step returns persist
3. **Ensure idempotency** - Steps may retry; check if operations already completed
4. **Keep steps granular** - One API call per step for better durability
5. **Name steps deterministically** - No timestamps/random values; names are cache keys
6. **Don't mutate events** - Changes to `event.payload` aren't persisted
7. **Wrap side effects in steps** - `Math.random()`, workflow creation, etc. must be in `step.do`
8. **Keep returns under 1 MiB** - Store large data in R2/KV, return references
## Step Patterns
### Basic Step Execution
```typescript
const result = await step.do('step name', async () => {
// Step logic here
return { data: 'persisted result' };
});
// Use result in subsequent steps
console.log(result.data);
```
**Key rules**:
- Always `await` step.do() calls
- Step results are automatically persisted
- Steps are idempotent - re-running uses cached result
- Step names must be unique within a workflow instance
### Step with Retries
```typescript
await step.do(
'api call with retries',
{
retries: {
limit: 5, // Max retry attempts
delay: '5 second', // Initial delay between retries
backoff: 'exponential', // 'exponential', 'linear', or 'constant'
},
},
async () => {
const response = await fetch('https://api.example.com/data');
if (!response.ok) {
throw new Error(`API error: ${response.status}`);
}
return await response.json();
},
);
```
### Step with Timeout
```typescript
await step.do(
'long running operation',
{
timeout: '15 minutes', // Max execution time for this step
},
async () => {
// Long-running work here
},
);
```
### Sleep for Duration
```typescript
// Pause workflow execution
await step.sleep('wait for processing', '5 minutes');
// Supported formats: '30 second', '5 minute', '2 hour'
```
**Use sleep for**:
- Rate limiting between API calls
- Waiting for external systems to process
- Human-in-the-loop delays
## Instance Management
### Creating Workflow Instances
```typescript
// Create with auto-generated ID
const instance = await env.MY_WORKFLOW.create({
params: { email: '[email protected]' },
});
// Create with custom ID (must be unique)
const instance = await env.MY_WORKFLOW.create({
id: crypto.randomUUID(),
params: { email: '[email protected]', metadata: {} },
});
```
### Getting Instance Status
```typescript
// Retrieve existing instanceRelated in Backend & APIs
jfrog
IncludedInteract with the JFrog Platform via the JFrog CLI and REST/GraphQL APIs. Use this skill when the user wants to manage Artifactory repositories, upload or download artifacts, manage builds, configure permissions, manage users and groups, work with access tokens, configure JFrog CLI servers, search artifacts, manage properties, set up replication, manage JFrog Projects, run security audits or scans, look up CVE details, query exposures scan results from JFrog Advanced Security, manage release bundles and lifecycle operations, aggregate or export platform data, or perform any JFrog Platform administration task. Also use when the user mentions jf, jfrog, artifactory, xray, distribution, evidence, apptrust, onemodel, graphql, workers, mission control, curation, advanced security, exposures, or any JFrog product name.
cupynumeric-migration-readiness
IncludedPre-migration readiness assessor for porting NumPy to cuPyNumeric. Use BEFORE substantial porting work begins when the user asks whether code will scale on GPU, whether they should migrate to cuPyNumeric, which NumPy patterns transfer cleanly, what must be refactored before porting, or mentions pre-port assessment, scaling analysis, or refactor planning. Inspect the user's source code, look up NumPy usage, cross-reference the cuPyNumeric API support manifest, and distinguish distributed-scaling-friendly patterns from blockers such as unsupported APIs, scalar synchronization, host round-trips, Python/object-heavy control flow, shape/data-dependent branching, and in-place mutation hazards. Produce a verdict of READY, LIGHT REFACTOR, SIGNIFICANT REFACTOR, or NOT RECOMMENDED, with concrete refactor pointers.
alibabacloud-data-agent-skill
IncludedInvoke Alibaba Cloud Apsara Data Agent for Analytics via CLI to perform natural language-driven data analysis on enterprise databases. Data Agent for Analytics is an intelligent data analysis agent developed by Alibaba Cloud Database team for enterprise users. It automatically completes requirement analysis, data understanding, analysis insights, and report generation based on natural language descriptions. This tool supports: discovering data resources (instances/databases/tables) managed in DMS, initiating query or deep analysis sessions, real-time progress tracking, and retrieving analysis conclusions and generated reports. Use this Skill when users need to query databases, analyze data trends, generate data reports, ask questions in natural language, or mention "Data Agent", "data analysis", "database query", "SQL analysis", "data insights".
token-optimizer
IncludedReduce OpenClaw token usage and API costs through smart model routing, heartbeat optimization, budget tracking, and native 2026.2.15 features (session pruning, bootstrap size limits, cache TTL alignment). Use when token costs are high, API rate limits are being hit, or hosting multiple agents at scale. The 4 executable scripts (context_optimizer, model_router, heartbeat_optimizer, token_tracker) are local-only — no network requests, no subprocess calls, no system modifications. Reference files (PROVIDERS.md, config-patches.json) document optional multi-provider strategies that require external API keys and network access if you choose to use them. See SECURITY.md for full breakdown.
resend-cli
IncludedUse this skill when the task is specifically about operating Resend from an AI agent, terminal session, or CI job via the official resend CLI: installing/authenticating the CLI, sending/listing/updating/cancelling emails, batch sends, domains and DNS, webhooks and local listeners, inbound receiving, contacts, topics, segments, broadcasts, templates, API keys, profiles, or debugging Resend CLI/API failures. Trigger on mentions of Resend CLI, `resend`, `resend doctor`, `resend emails send`, `resend domains`, `resend webhooks listen`, `resend emails receiving`, or agent-friendly terminal automation.
alibabacloud-odps-maxframe-coding
IncludedUse this skill for MaxFrame SDK development and documentation navigation on Alibaba Cloud MaxCompute (ODPS). Helps answer MaxFrame API, concept, official example, and supported pandas API questions; create data processing programs; read/write MaxCompute tables; debug jobs (remote or local); and build custom DPE runtime images. Trigger when users mention MaxFrame, MaxCompute with MaxFrame, ODPS table processing, DPE runtime, MaxFrame docs/examples, DataFrame/Tensor operations, or GPU runtime setup. Works for both English and Chinese queries about Alibaba Cloud data processing with MaxFrame.