Starter template for building Workflow DevKit Worlds
npm install @workflow-worlds/starter


A complete in-memory World implementation that serves as a starting point for building custom Worlds.
- In-Memory Storage - Runs, steps, events, and hooks stored in Maps
- Workflow 4.1 Contract - Event-sourced transitions via storage.events.create(...)
- Legacy Run Compatibility - Safe handling for pre-event-sourced runs
- setTimeout Queue - Simple queue processing via HTTP callbacks
- In-Memory Streamer - Real-time output streaming with event emitters
- Full Test Coverage - Passes all @workflow/world-testing suites
- Well-Documented - TODO markers show where to add your implementation
``bash`
npm install @workflow-worlds/starteror
pnpm add @workflow-worlds/starter
- New writes should be implemented in storage.events.create(...).storage.runs
- , storage.steps, and storage.hooks should primarily provide read/list access for runtime use.listStreamsByRunId(runId)
- For streamer parity with production worlds, implement in your backend adaptation.
- Keep legacy-run behavior explicitly tested if you support upgrades from older data.
`typescript
import { createWorld } from '@workflow-worlds/starter';
const world = createWorld();
// Start queue processing
await world.start();
`
The starter is designed to be copied and modified:
`bash`
cp -r packages/starter my-world
cd my-world
`json`
{
"name": "@myorg/world-custom",
"description": "My custom World implementation"
}
`bash`
pnpm install
pnpm build
pnpm test
Each component has TODO markers showing where to add your backend:
| File | Replace With |
|------|--------------|
| src/storage.ts | Database (MongoDB, PostgreSQL, etc.) |src/queue.ts
| | Job queue (BullMQ, SQS, etc.) |src/streamer.ts
| | Streaming (Redis Streams, WebSockets, etc.) |
Run tests after each change to catch issues early:
`bash`
pnpm test
``
src/
├── index.ts # World factory and exports
├── storage.ts # Storage implementation (runs, steps, events, hooks)
├── queue.ts # Queue implementation with HTTP callbacks
├── streamer.ts # Output streaming implementation
└── utils.ts # Shared utilities (ID generation, cloning)
`typescript
interface StarterWorldConfig {
// Base URL for HTTP callbacks
// Default: http://localhost:${PORT}
baseUrl?: string;
// Port for HTTP callbacks
// Default: process.env.PORT ?? 3000
port?: number;
}
`
Set the WORKFLOW_TARGET_WORLD environment variable:
`bash`
WORKFLOW_TARGET_WORLD=@workflow-worlds/starter pnpm dev
Or export the factory function:
`typescript
// world.ts
import { createWorld } from '@workflow-worlds/starter';
export default createWorld;
`
The starter passes all five test suites from @workflow/world-testing:
| Suite | Description | Duration |
|-------|-------------|----------|
| addition | Basic workflow execution | ~12s |
| idempotency | State reconstruction with 110 steps | ~30s |
| hooks | Hook/resume mechanism | ~15s |
| errors | Retry semantics | ~30s |
| nullByte | Binary data handling | ~5s |
Run tests:
`bash`
pnpm test
The starter uses structuredClone() for all returned objects to prevent mutation issues:
`typescript`
// storage.ts
return deepClone(run); // Not the original object
Messages queued before start() are buffered and processed once started:
`typescript`
const world = createWorld();
await world.queue(...); // Buffered
await world.start(); // Now processed
Uses monotonic ULIDs with prefixes for all entities:
`typescriptwrun_${generateUlid()}
const runId = ;step_${generateUlid()}
const stepId = ;``
MIT