Skip to content
Open
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
17 changes: 15 additions & 2 deletions .clinerules
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import { z } from 'zod';

const myWorkflow = workflow(
'workflow-id',
async ({ step, input, runId, workflowId, timeline, logger }) => {
async ({ step, input, runId, workflowId, timeline, logger, schedule }) => {
const result = await step.run('step-1', async () => {
return { processed: input.data };
});
Expand All @@ -45,6 +45,8 @@ const myWorkflow = workflow(
inputSchema: z.object({ data: z.string() }),
timeout: 60000,
retries: 3,
cron: '*/15 * * * *', // cron expression string (UTC)
// or: cron: { expression: '*/15 * * * *', timezone: 'America/New_York' },
}
);
```
Expand All @@ -67,7 +69,7 @@ await engine.start();
- `step.run(stepId, handler)` - Durable step, runs exactly once, result persisted in PostgreSQL
- `step.waitFor(stepId, { eventName, timeout?, schema? })` - Pause and wait for an external event
- `step.pause(stepId)` - Manual pause; resume with `engine.resumeWorkflow()`
- `step.waitUntil(stepId, { date })` - Wait until a date (not yet implemented)
- `step.waitUntil(stepId, { date })` - Wait until a specific date

### Engine methods

Expand All @@ -94,6 +96,17 @@ enum StepType { PAUSE = 'pause', RUN = 'run', WAIT_FOR = 'waitFor', WAIT_UNTIL =
- `WorkflowEngineError(message, workflowId?, runId?, cause?)` - Base error
- `WorkflowRunNotFoundError(runId?, workflowId?)` - Run not found

## Cron Workflows

Workflows can run on a cron schedule via the `cron` option on `workflow()`. Uses pg-boss `schedule()` under the hood.

- `cron` option accepts a string (`'*/15 * * * *'`) or object (`{ expression, timezone? }`)
- `CronConfig`: `{ expression: string, timezone?: string }`
- `ScheduleContext`: `{ timestamp: Date, lastTimestamp: Date | undefined, timezone: string }` — available as `schedule` on workflow context for cron-triggered runs. Built at runtime from `run.createdAt` and latest completed run.
- `WorkflowRun` stores `cron: string | null` and `timezone: string | null` as flat columns (no nested JSON)
- Cron-triggered runs are identified by `cron !== null` on the `WorkflowRun`
- Post-start registration: `registerWorkflow()` after `start()` automatically sets up cron schedule

## AI & Agent Workflows

pg-workflows is ideal for AI agents and LLM pipelines. Key patterns:
Expand Down
17 changes: 15 additions & 2 deletions .cursorrules
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import { z } from 'zod';

const myWorkflow = workflow(
'workflow-id',
async ({ step, input, runId, workflowId, timeline, logger }) => {
async ({ step, input, runId, workflowId, timeline, logger, schedule }) => {
const result = await step.run('step-1', async () => {
return { processed: input.data };
});
Expand All @@ -49,6 +49,8 @@ const myWorkflow = workflow(
inputSchema: z.object({ data: z.string() }),
timeout: 60000,
retries: 3,
cron: '*/15 * * * *', // cron expression string (UTC)
// or: cron: { expression: '*/15 * * * *', timezone: 'America/New_York' },
}
);
```
Expand All @@ -71,7 +73,7 @@ await engine.start();
- `step.run(stepId, handler)` - Durable step, runs exactly once, result persisted in PostgreSQL
- `step.waitFor(stepId, { eventName, timeout?, schema? })` - Pause and wait for an external event
- `step.pause(stepId)` - Manual pause; resume with `engine.resumeWorkflow()`
- `step.waitUntil(stepId, { date })` - Wait until a date (not yet implemented)
- `step.waitUntil(stepId, { date })` - Wait until a specific date

### Engine methods

Expand All @@ -98,6 +100,17 @@ enum StepType { PAUSE = 'pause', RUN = 'run', WAIT_FOR = 'waitFor', WAIT_UNTIL =
- `WorkflowEngineError(message, workflowId?, runId?, cause?)` - Base error
- `WorkflowRunNotFoundError(runId?, workflowId?)` - Run not found

## Cron Workflows

Workflows can run on a cron schedule via the `cron` option on `workflow()`. Uses pg-boss `schedule()` under the hood.

- `cron` option accepts a string (`'*/15 * * * *'`) or object (`{ expression, timezone? }`)
- `CronConfig`: `{ expression: string, timezone?: string }`
- `ScheduleContext`: `{ timestamp: Date, lastTimestamp: Date | undefined, timezone: string }` — available as `schedule` on workflow context for cron-triggered runs. Built at runtime from `run.createdAt` and latest completed run.
- `WorkflowRun` stores `cron: string | null` and `timezone: string | null` as flat columns (no nested JSON)
- Cron-triggered runs are identified by `cron !== null` on the `WorkflowRun`
- Post-start registration: `registerWorkflow()` after `start()` automatically sets up cron schedule

## AI & Agent Workflows

pg-workflows is ideal for AI agents and LLM pipelines. Key patterns:
Expand Down
17 changes: 15 additions & 2 deletions .windsurfrules
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ import { z } from 'zod';

const myWorkflow = workflow(
'workflow-id',
async ({ step, input, runId, workflowId, timeline, logger }) => {
async ({ step, input, runId, workflowId, timeline, logger, schedule }) => {
const result = await step.run('step-1', async () => {
return { processed: input.data };
});
Expand All @@ -45,6 +45,8 @@ const myWorkflow = workflow(
inputSchema: z.object({ data: z.string() }),
timeout: 60000,
retries: 3,
cron: '*/15 * * * *', // cron expression string (UTC)
// or: cron: { expression: '*/15 * * * *', timezone: 'America/New_York' },
}
);
```
Expand All @@ -67,7 +69,7 @@ await engine.start();
- `step.run(stepId, handler)` - Durable step, runs exactly once, result persisted in PostgreSQL
- `step.waitFor(stepId, { eventName, timeout?, schema? })` - Pause and wait for an external event
- `step.pause(stepId)` - Manual pause; resume with `engine.resumeWorkflow()`
- `step.waitUntil(stepId, { date })` - Wait until a date (not yet implemented)
- `step.waitUntil(stepId, { date })` - Wait until a specific date

### Engine methods

Expand All @@ -94,6 +96,17 @@ enum StepType { PAUSE = 'pause', RUN = 'run', WAIT_FOR = 'waitFor', WAIT_UNTIL =
- `WorkflowEngineError(message, workflowId?, runId?, cause?)` - Base error
- `WorkflowRunNotFoundError(runId?, workflowId?)` - Run not found

## Cron Workflows

Workflows can run on a cron schedule via the `cron` option on `workflow()`. Uses pg-boss `schedule()` under the hood.

- `cron` option accepts a string (`'*/15 * * * *'`) or object (`{ expression, timezone? }`)
- `CronConfig`: `{ expression: string, timezone?: string }`
- `ScheduleContext`: `{ timestamp: Date, lastTimestamp: Date | undefined, timezone: string }` — available as `schedule` on workflow context for cron-triggered runs. Built at runtime from `run.createdAt` and latest completed run.
- `WorkflowRun` stores `cron: string | null` and `timezone: string | null` as flat columns (no nested JSON)
- Cron-triggered runs are identified by `cron !== null` on the `WorkflowRun`
- Post-start registration: `registerWorkflow()` after `start()` automatically sets up cron schedule

## AI & Agent Workflows

pg-workflows is ideal for AI agents and LLM pipelines. Key patterns:
Expand Down
61 changes: 59 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ src/
│ └── migration.ts # Schema migrations
└── tests/ # Test utilities
examples/
└── basic.ts # Example usage
├── basic.ts # Example usage
└── cron.ts # Cron workflow example
```

## Commands
Expand Down Expand Up @@ -66,13 +67,16 @@ import { z } from 'zod';

const myWorkflow = workflow(
'workflow-id', // unique string ID
async ({ step, input, runId, workflowId, timeline, logger }) => {
async ({ step, input, runId, workflowId, timeline, logger, schedule }) => {
// workflow body with step calls
// `schedule` is populated for cron-triggered runs
},
{
inputSchema: z.object({ /* ... */ }), // optional Zod schema
timeout: 60000, // optional, milliseconds
retries: 3, // optional, max retry count
cron: '*/15 * * * *', // cron expression string (UTC)
// or: cron: { expression: '*/15 * * * *', timezone: 'America/New_York' },
}
);
```
Expand Down Expand Up @@ -202,6 +206,8 @@ type WorkflowRun = {
retryCount: number;
maxRetries: number;
jobId: string | null;
cron: string | null;
timezone: string | null;
};

type WorkflowRunProgress = WorkflowRun & {
Expand All @@ -227,6 +233,57 @@ class WorkflowRunNotFoundError extends WorkflowEngineError {}
| `WORKFLOW_RUN_WORKERS` | Number of worker processes | `3` |
| `WORKFLOW_RUN_EXPIRE_IN_SECONDS` | Job expiration time in seconds | `300` |

## Cron Workflows

Workflows can be scheduled to run on a cron expression using the `cron` option. The engine uses pg-boss `schedule()` under the hood.

### CronConfig

The `cron` option accepts a string or an object:

```typescript
// String shorthand (defaults to UTC)
cron: '*/15 * * * *'

// Object with explicit timezone
cron: { expression: '*/15 * * * *', timezone: 'America/New_York' }

type CronConfig = {
expression: string; // standard cron expression
timezone?: string; // IANA timezone, defaults to 'UTC'
};
```

### ScheduleContext

Cron-triggered runs receive a `schedule` object on the workflow context. The `timestamp` is derived from `run.createdAt` and `lastTimestamp` is queried from the latest completed run at execution time.

```typescript
type ScheduleContext = {
timestamp: Date; // when this cron trigger fired
lastTimestamp: Date | undefined; // when the last successful cron run completed
timezone: string; // the configured timezone
};
```

### Cron workflow example

```typescript
const sync = workflow('sync-data', async ({ step, schedule, logger }) => {
const since = schedule?.lastTimestamp ?? new Date(0);
const data = await step.run('fetch', async () => fetchSince(since));
await step.run('write', async () => writeToDB(data));
return { synced: data.length };
}, {
cron: '*/15 * * * *', // every 15 minutes, UTC
retries: 3,
});
```

### Post-start registration

Calling `engine.registerWorkflow()` after `engine.start()` will automatically set up the cron schedule if the workflow has a `cron` config.

## AI & Agent Workflow Patterns

pg-workflows is well-suited for AI agents and LLM pipelines because LLM calls are slow, expensive, and unreliable - exactly the work that benefits most from durable execution.
Expand Down
61 changes: 59 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ src/
│ └── migration.ts # Schema migrations
└── tests/ # Test utilities
examples/
└── basic.ts # Example usage
├── basic.ts # Example usage
└── cron.ts # Cron workflow example
```

## Commands
Expand Down Expand Up @@ -67,13 +68,16 @@ import { z } from 'zod';

const myWorkflow = workflow(
'workflow-id', // unique string ID
async ({ step, input, runId, workflowId, timeline, logger }) => {
async ({ step, input, runId, workflowId, timeline, logger, schedule }) => {
// workflow body with step calls
// `schedule` is populated for cron-triggered runs
},
{
inputSchema: z.object({ /* ... */ }), // optional Zod schema
timeout: 60000, // optional, milliseconds
retries: 3, // optional, max retry count
cron: '*/15 * * * *', // cron expression string (UTC)
// or: cron: { expression: '*/15 * * * *', timezone: 'America/New_York' },
}
);
```
Expand Down Expand Up @@ -239,6 +243,8 @@ type WorkflowRun = {
retryCount: number;
maxRetries: number;
jobId: string | null;
cron: string | null;
timezone: string | null;
};

type WorkflowRunProgress = WorkflowRun & {
Expand All @@ -264,6 +270,57 @@ class WorkflowRunNotFoundError extends WorkflowEngineError {}
| `WORKFLOW_RUN_WORKERS` | Number of worker processes | `3` |
| `WORKFLOW_RUN_EXPIRE_IN_SECONDS` | Job expiration time in seconds | `300` |

## Cron Workflows

Workflows can be scheduled to run on a cron expression using the `cron` option. The engine uses pg-boss `schedule()` under the hood.

### CronConfig

The `cron` option accepts a string or an object:

```typescript
// String shorthand (defaults to UTC)
cron: '*/15 * * * *'

// Object with explicit timezone
cron: { expression: '*/15 * * * *', timezone: 'America/New_York' }

type CronConfig = {
expression: string; // standard cron expression
timezone?: string; // IANA timezone, defaults to 'UTC'
};
```

### ScheduleContext

Cron-triggered runs receive a `schedule` object on the workflow context. The `timestamp` is derived from `run.createdAt` and `lastTimestamp` is queried from the latest completed run at execution time.

```typescript
type ScheduleContext = {
timestamp: Date; // when this cron trigger fired
lastTimestamp: Date | undefined; // when the last successful cron run completed
timezone: string; // the configured timezone
};
```

### Cron workflow example

```typescript
const sync = workflow('sync-data', async ({ step, schedule, logger }) => {
const since = schedule?.lastTimestamp ?? new Date(0);
const data = await step.run('fetch', async () => fetchSince(since));
await step.run('write', async () => writeToDB(data));
return { synced: data.length };
}, {
cron: '*/15 * * * *', // every 15 minutes, UTC
retries: 3,
});
```

### Post-start registration

Calling `engine.registerWorkflow()` after `engine.start()` will automatically set up the cron schedule if the workflow has a `cron` config.

## AI & Agent Workflow Patterns

pg-workflows is well-suited for AI agents and LLM pipelines because LLM calls are slow, expensive, and unreliable - exactly the work that benefits most from durable execution.
Expand Down
Loading
Loading