Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 14 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,31 @@ Durable, replayable multi-step operations for Rivet Actors.
**[Documentation](https://rivet.dev/workflows/docs)** · **[Website](https://rivet.dev/workflows)** · **[Discord](https://rivet.dev/discord)**

```sh
pnpm add @rivet-dev/workflows rivetkit
pnpm add @rivet-dev/workflows
```

```ts
import { workflow } from "@rivet-dev/workflows";
import { setup, workflow } from "@rivet-dev/workflows";

export const report = workflow({
state: { status: "pending" as "pending" | "complete" },
run: async (ctx) => {
await ctx.step("generate", async (step) => {
step.log.info("generating report");
step.state.status = "complete";
});
},
actions: {
status: (ctx) => ctx.state,
},
});

export const registry = setup({ use: { report } });
```

The package preserves the existing workflow history encoding and uses only
RivetKit's public workflow-host capabilities. RivetKit continues to own the
internal SQLite schema and its migrations.
RivetKit's public workflow-host capabilities. It re-exports RivetKit, and package
managers install its compatible peer automatically, so workflow actors and
regular `actor(...)` definitions can share the same registry without another
direct dependency. RivetKit continues to own the internal SQLite schema and its
migrations.
4 changes: 3 additions & 1 deletion docs/content/docs/index.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@ Use workflows for durable, multi-step execution with replay safety.

## What are workflows?

A workflow is a durable, replayable run handler.
A workflow is a durable, replayable actor definition. It supports the full actor
configuration, including actions and lifecycle hooks, while its `run` function
uses replay-safe workflow primitives.

- Survives restarts: workflow progress is saved automatically.
- Re-runs safely: replay follows the same recorded steps.
Expand Down
19 changes: 0 additions & 19 deletions packages/workflows/README.md

This file was deleted.

4 changes: 2 additions & 2 deletions packages/workflows/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,15 +64,15 @@
"vbare": "^0.0.4"
},
"peerDependencies": {
"rivetkit": ">=2.4.0 <3"
"rivetkit": ">=2.3.11 <2.4.0"
},
"devDependencies": {
"@bare-ts/tools": "^0.13.0",
"@types/node": "^22.13.1",
"commander": "^12.0.0",
"legacy-rivetkit": "npm:rivetkit@2.3.7",
"legacy-workflow-engine": "npm:@rivetkit/workflow-engine@2.3.7",
"rivetkit": "0.0.0-feat-workflows-public-host-apis.1550fe4",
"rivetkit": "2.3.11",
"tsup": "^8.4.0",
"tsx": "^4.7.0",
"typescript": "^5.7.3",
Expand Down
9 changes: 9 additions & 0 deletions packages/workflows/src/mod.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,11 @@
export * from "rivetkit";
export * from "./index.js";
export type {
WorkflowBranchContextOf,
WorkflowContextOf,
WorkflowLoopContextOf,
WorkflowStepContextOf,
} from "./rivetkit/context.js";
export * from "./rivetkit/mod.js";
// Prefer workflow-specific meanings for names that also exist in RivetKit.
export type { WorkflowState } from "./types.js";
18 changes: 10 additions & 8 deletions packages/workflows/src/rivetkit/inspector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import * as transport from "rivetkit/experimental/inspector/workflow";
import {
encodeWorkflowHistoryTransport,
encodeWorkflowInspectorValue,
type WorkflowHistoryBytes,
type WorkflowInspectorAdapter,
} from "rivetkit/experimental/inspector/workflow";
import type {
Expand All @@ -21,7 +22,7 @@ function assertUnreachable(value: never): never {
throw new Error(`Unexpected workflow Inspector value: ${String(value)}`);
}

type HistoryListener = (history: ArrayBuffer) => void;
type HistoryListener = (history: WorkflowHistoryBytes) => void;

function createHistoryEmitter() {
const listeners = new Set<HistoryListener>();
Expand All @@ -31,7 +32,7 @@ function createHistoryEmitter() {
listeners.add(listener);
return () => listeners.delete(listener);
},
emit: (history: ArrayBuffer) => {
emit: (history: WorkflowHistoryBytes) => {
for (const listener of listeners) {
listener(history);
}
Expand All @@ -44,16 +45,17 @@ export function createWorkflowInspectorAdapter(): {
update: (snapshot: WorkflowHistorySnapshot) => void;
setGetState: (fn: () => Promise<WorkflowState | null>) => void;
setReplayFromStep: (
fn: (entryId?: string) => Promise<ArrayBuffer | null>,
fn: (entryId?: string) => Promise<WorkflowHistoryBytes | null>,
) => void;
} {
const emitter = createHistoryEmitter();
let history: ArrayBuffer | null = null;
let history: WorkflowHistoryBytes | null = null;
let getState: () => Promise<WorkflowState | null> = async () => null;
let replayFromStep: (entryId?: string) => Promise<ArrayBuffer | null> =
async () => {
throw new Error("Workflow replay controls are not initialized");
};
let replayFromStep: (
entryId?: string,
) => Promise<WorkflowHistoryBytes | null> = async () => {
throw new Error("Workflow replay controls are not initialized");
};

const adapter: WorkflowInspectorAdapter = {
getHistory: () => history,
Expand Down
Loading
Loading