* chore: bump next to 16.2.1
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* test: run deferred Next dev e2e assertions on stable
Bump Next.js to 16.2.1 in docs and swc-playground and update lockfile.
* fix(next): copy all deferred step sources for step-mode transforms
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: JJ Kasper <jj@jjsweb.site>
Co-authored-by: Peter Wielander <mittgfu@gmail.com>
* feat: export semantic error types and add API reference documentation
Add missing error exports (HookNotFoundError, EntityConflictError,
RunExpiredError, TooEarlyError, ThrottleError, RunNotSupportedError,
WorkflowWorldError) to workflow/internal/errors. Create new error
classes for world-level semantics. Tighten TSDoc comments on all
error classes. Add API reference docs for all error types.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: use @setup declarations, workflow/errors import, and errors/ doc section
- Replace @skip-typecheck with proper `declare` + `// @setup` lines
so code samples are typechecked but setup lines hidden from readers
- Add `workflow/errors` export to package.json (public API, replaces
`workflow/internal/errors` in docs)
- Add `workflow/errors` path mapping in docs-typecheck type-checker
- Add HookConflictError to re-export list
- Move all error docs under api-reference/workflow/errors/ subdirectory
- Update all internal cross-references and links
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: move error docs to top-level workflow-errors section
- Move semantic error docs to api-reference/workflow-errors/ (matching
the workflow/errors import path, like workflow-api for workflow/api)
- Keep FatalError and RetryableError in api-reference/workflow/ since
they're imported from workflow, not workflow/errors
- Fix all cross-reference links
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: update HTTP debug logger JSDoc to clarify scope
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: make TooEarlyError.retryAfter a number (seconds) matching WorkflowWorldError
TooEarlyError.retryAfter is now seconds (number) instead of a Date,
consistent with ThrottleError and WorkflowWorldError. The conversion
from seconds to Date is done at the consumer site (step-handler) rather
than at construction time.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address review feedback on docs accuracy
- WorkflowWorldError docs: add status, code, url, retryAfter properties
to TSDoc; clarify that .is() only matches direct instances (not
subclasses); use instanceof in catch-all example
- TooEarlyError/ThrottleError docs: mark retryAfter as optional (?)
to match actual type definitions
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* Set maxDuration: "max" in vc-config for workflow functions
* Use maxDuration: 60 for flow route, "max" for step/webhook
* Remove explicit maxDuration from webhook route, rely on plan default
## Summary
When `WORKFLOW_PUBLIC_MANIFEST=1` is set, each framework builder exposes the workflow manifest at `/.well-known/workflow/v1/manifest.json` via the most appropriate mechanism for the framework:
- **Next.js**: Copies manifest to `public/.well-known/workflow/v1/manifest.json` (served as a static file)
- **SvelteKit**: Copies manifest to `static/.well-known/workflow/v1/manifest.json` (served as a static file)
- **Vercel Build Output API** (example workbench): Copies manifest to `.vercel/output/static/.well-known/workflow/v1/manifest.json` (served as a static file)
- **Nitro** (vite, hono, express, fastify, nuxt, nitro-v2, nitro-v3): Registers a virtual handler that reads and serves the manifest JSON
- **Astro**: Generates a `manifest.json.js` page route that returns the manifest JSON
- **NestJS**: Adds a `@Get('manifest.json')` endpoint on the `WorkflowController` (gated by the env var at runtime)
### Other changes
- `BaseBuilder.createManifest()` now returns the manifest JSON string so framework builders can use it
- Added `shouldExposePublicManifest` getter to `BaseBuilder`
- Fixed Astro `LocalBuilder` which was missing the `createManifest()` call that all other framework builders have
- Removed unused `public/` directory and static file copy from the example workbench build script
- Added `WORKFLOW_PUBLIC_MANIFEST` to `turbo.json` build task env so Vercel builds can access it
- Added generated manifest paths to `.gitignore`
* Bump Next.js and React in workbenches
- Next.js: 16.0.10 → 16.1.6 in nextjs-turbopack, nextjs-webpack, swc-playground workbenches
- Next.js: 16.0.10 → 16.1.6 in @workflow/next devDependencies (for type compatibility)
- React/React-DOM: ^19.0.0/19.2.1 → 19.2.4
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Add changeset
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Fixed a bug in module specifier resolution and added support for package subpath exports in workflow IDs.
### What changed?
- Fixed a caching bug in the module specifier resolution system that could cause incorrect IDs
- Added support for subpath exports in package IDs (e.g., `workflow/internal/builtins@4.0.0`)
- Improved module resolution by passing absolute file paths to the SWC transform
- Enhanced manifest merging to properly combine results from both workflow and step bundles
- Updated builders to return and merge manifests from both workflow and step bundles
### How to test?
1. Build a project that uses subpath exports in packages
2. Verify that workflow IDs correctly include the subpath (e.g., `workflow/internal/builtins@4.0.0`)
3. Test with a project that has multiple builds to ensure module specifier caching works correctly
### Why make this change?
This change addresses an issue where the module specifier cache could return incorrect results, leading to inconsistent workflow IDs. It also adds support for packages with multiple entry points through subpath exports, ensuring that steps with the same name in different subpaths don't collide. This improves the reliability of cross-bundle references and makes the system more robust when working with complex package structures.
## Summary
This PR changes how the SWC compiler generates IDs for workflows, steps, and classes. Instead of using raw file paths, IDs are now based on **Node.js module specifiers** when the file belongs to a package (either in `node_modules` or a workspace package).
## Motivation
Previously, IDs were generated using file paths like `step//src/jobs/order.ts//fetchData`. This caused several issues:
1. **Package exports conditions**: When a package uses conditional exports (e.g., `"workflow"` vs `"default"` conditions in `package.json`), the same import specifier can resolve to different files. Using file paths meant IDs could differ based on which export condition was used.
2. **Cross-bundle consistency**: Classes serialized in one bundle couldn't be deserialized in another if the file paths differed.
3. **Version tracking**: No way to include package versions in IDs for cache invalidation.
## Changes
### New ID Format
IDs now use the format `{type}//{modulePath}//{identifier}` where `modulePath` is either:
- A **module specifier** like `point@0.0.1` or `@myorg/shared@1.2.3` for package files
- A **relative path** prefixed with `./` like `./src/jobs/order` for local app files
Examples:
- `step//workflow@4.0.1-beta.50//fetch` (SDK step)
- `step//./workflows/order//processOrder` (local step)
- `class//point@0.0.1//Point` (package class)
- `class//./src/models/User//User` (local class)
### New Module Specifier Resolution
Added `packages/builders/src/module-specifier.ts` which:
- Detects if a file is in `node_modules` or a workspace package
- Finds the nearest `package.json` and extracts name/version
- Returns the module specifier for the SWC plugin to use
### SWC Plugin Changes
- Added `moduleSpecifier` option to plugin config
- Updated `naming.rs` to support both module specifiers and relative paths
- Added `get_module_path()` helper that uses specifier when available, falls back to `./filename` format
### Special Cases
- **Builtin functions** (`__builtin_*`): Continue to use just the function name as the ID for stable, version-independent lookup from the workflow VM runtime.
## Testing
- Updated all 125+ SWC plugin test fixtures to use new ID format
- Added tests for module specifier resolution
- Added tests for Windows path normalization in naming
## Breaking Changes
This is technically a breaking change for any persisted workflow runs that reference the old ID format. However, since IDs are internal implementation details and not user-facing, this should not affect end users.
## Files Changed
- `packages/builders/src/module-specifier.ts` - **NEW**: Module specifier resolution logic
- `packages/builders/src/apply-swc-transform.ts` - Pass module specifier to SWC plugin
- `packages/builders/src/base-builder.ts` - Use `getImportPath` for virtual entry imports
- `packages/swc-plugin-workflow/transform/src/lib.rs` - Accept and use module specifier
- `packages/swc-plugin-workflow/transform/src/naming.rs` - New ID formatting with module paths
- `packages/swc-plugin-workflow/spec.md` - Updated documentation
- `packages/core/e2e/e2e.test.ts` - Updated test assertions for new ID format
Added automatic discovery for custom classes with workflow serialization, allowing serialization classes to be defined in separate files without requiring explicit directives.
### What changed?
- Added detection for files containing custom class serialization patterns:
- Files importing from `@workflow/serde`
- Files using `Symbol.for('workflow-serialize')` or `Symbol.for('workflow-deserialize')`
- Created shared utilities in `transform-utils.ts` for consistent pattern detection across all build tools
- Updated Next.js, Nitro, Rollup, and Vite plugins to use the new detection patterns
- Added exclusion logic to prevent re-processing of generated workflow files
- Added tests to verify the pattern detection works correctly
- Updated documentation in the SWC plugin spec to explain the new discovery mechanism
### How to test?
1. Create a class with custom serialization in a separate file:
```js
// models/point.js
export class Point {
constructor(x, y) {
this.x = x;
this.y = y;
}
static [Symbol.for('workflow-serialize')](instance) {
return { x: instance.x, y: instance.y };
}
static [Symbol.for('workflow-deserialize')](data) {
return new Point(data.x, data.y);
}
}
```
1. Import and use this class in a workflow or step file:
```js
'use workflow';
import { Point } from '../models/point';
export function myWorkflow() {
const point = new Point(10, 20);
return point;
}
```
1. Verify the class is properly serialized when passed between client and server
### Why make this change?
Previously, files containing custom serialization classes needed to include a `'use step'` directive to be discovered and transformed, even if they weren't actual step functions. This was unintuitive and could lead to confusion.
This change allows for a more natural code organization pattern where model classes with serialization can be defined in their own files without requiring directives. The build system will automatically discover and transform these files to ensure the serialization works correctly when the classes are used in workflows or steps.
* perf(builders): optimize workflow discovery with hybrid SWC approach
Apply SWC transforms only to files containing workflow/step directives
instead of all files. Uses regex for fast filtering, then SWC where needed.
- esbuild follows imports to build dependency graph
- regex detects 'use workflow'/'use step' directives
- SWC applied only to files with directives (<1% typically)
- other files use esbuild's built-in TS handling
* Remove blank line
* feat(next): add configurable `dirs` option to withWorkflow
Allow users to specify which directories to scan for workflow directives,
helping reduce memory usage and build times in large Next.js applications.
- Add `dirs` option that overrides the default directories
- Document all configuration options in API reference
- Add troubleshooting guide for OOM errors during build
* fix(docs): add missing imports in withWorkflow code example
Add missing import statements and nextConfig declaration to the
troubleshooting code example to fix docs typecheck.
* docs: move OOM troubleshooting to getting-started/next
Move the OOM troubleshooting section from the API reference to the
existing troubleshooting section in docs/getting-started/next.mdx
for better discoverability.
* move dirs inside workflow config
* Add workflow skill for Claude Code
Add custom slash commands for Claude Code:
- /pr command for creating PRs following repo conventions
Add workflow skill with comprehensive documentation:
- Main SKILL.md with core concepts and quick reference
- Reference docs for frameworks, AI agents, patterns, errors, and API
Signed-off-by: johnlindquist <johnlindquist@gmail.com>
Signed-off-by: John Lindquist <johnlindquist@gmail.com>
* Update SKILL.md serialization docs for custom class support
Add documentation for custom class serialization using @workflow/serde
symbols (WORKFLOW_SERIALIZE/WORKFLOW_DESERIALIZE) and clarify what can
and cannot be serialized based on recent PR #762.
Signed-off-by: John Lindquist <johnlindquist@gmail.com>
* Fix incorrect API property names in SKILL.md
- Update sleep() example date from 2025 to 2027 (future date)
- Fix getWorkflowMetadata() to use correct properties: workflowRunId,
workflowStartedAt, url (not runId, workflowName)
- Fix getStepMetadata() to use correct property: attempt (not attemptNumber)
Signed-off-by: John Lindquist <johnlindquist@gmail.com>
* Move skills to skill/workflow directory structure
Reorganize skill files to support multiple skills under ./skill/<name>/
Signed-off-by: John Lindquist <johnlindquist@gmail.com>
* Rename skill to skills (plural)
Signed-off-by: John Lindquist <johnlindquist@gmail.com>
* Refactor skills to use bundled docs from node_modules
- Update SKILL.md to direct agents to search node_modules/workflow/docs/
- Remove manually-maintained reference docs (ai-agents, api-reference, frameworks, patterns)
- Keep common-errors.md for practical troubleshooting
- Add prepack/postpack hooks to bundle docs in npm packages:
- workflow: All docs from docs/content/docs/
- @workflow/ai: AI-specific docs
- @workflow/core: foundations, how-it-works, api-reference
- @workflow/next: Next.js setup docs
Signed-off-by: John Lindquist <johnlindquist@gmail.com>
* Add AI SDK step function guidance to SKILL.md
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Signed-off-by: John Lindquist <johnlindquist@gmail.com>
* Update SKILL.md formatting and add ecosystem section
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Signed-off-by: John Lindquist <johnlindquist@gmail.com>
* Align postpack scripts with AI SDK conventions
Use del-cli for postpack cleanup to match the AI SDK's cross-platform
approach. This ensures consistent tooling across both projects.
- Add del-cli ^5.1.0 to root devDependencies
- Update postpack in @workflow/core, @workflow/next, @workflow/ai, and
workflow packages from `rm -rf docs` to `del-cli docs`
Signed-off-by: John Lindquist <johnlindquist@gmail.com>
* Add workflow health command to debugging documentation
Document the CLI health check command for verifying workflow/step
endpoint connectivity during local development and production.
Signed-off-by: John Lindquist <johnlindquist@gmail.com>
* Address PR feedback: standardize on rm -rf and improve SKILL.md
- Remove del-cli dependency, use rm -rf consistently in postpack scripts
- Restructure SKILL.md to lead with "Prefer Step Functions" pattern
- Add sandbox limitations table for workflow-context workarounds
- Consolidate examples and remove duplication
Signed-off-by: John Lindquist <johnlindquist@gmail.com>
* Consolidate common-errors.md into SKILL.md
Move useful tips (serialization, streaming, debugging) into main skill
file and remove the separate common-errors.md reference file.
Signed-off-by: John Lindquist <johnlindquist@gmail.com>
---------
Signed-off-by: johnlindquist <johnlindquist@gmail.com>
Signed-off-by: John Lindquist <johnlindquist@gmail.com>
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Co-authored-by: Pranay Prakash <pranay.gp@gmail.com>
* Add SDK version to workflow run executionContext for observability
Wire `@workflow/core` package version through the `executionContext` field
when creating workflow runs. Display the version in the observability UI
attribute panel. Uses genversion for build-time version injection.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Fix workflowCoreVersion extraction and add turbo.json for caching
- Extract workflowCoreVersion from executionContext in hydrateResourceIO
before stripping the context (addresses Copilot review comment)
- Add turbo.json to include src/version.ts in build outputs for caching
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Update workflowCoreVersion display name to @workflow/core version
Use a display name mapping to render the attribute as "@workflow/core version"
in the observability UI for better readability.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>