Job
A job is a single pipeline run identified by ajobId string you provide. Every piece of state — status, checkpoint, and log entries — is scoped to that ID. Two pipelines with different jobId values are completely independent, even if they share the same phase definitions and adapters.
Phase
A phase is the smallest unit of work. It is a plain TypeScript object with two fields:name: string— unique within the phases array; used to look up the phase by name from the checkpointrun: (ctx: PhaseContext<TState>) => Promise<PhaseResult<TState>>— your business logic
Checkpoint<TState>. This makes them easy to test in isolation: construct a fake PhaseContext and call run directly.
Checkpoint
A checkpoint is a serialized snapshot of in-progress state. The storage layer persists it after every successful phase transition and whenever your phase callsctx.saveState().
runPipeline call reads the existing checkpoint and resumes from exactly that point — no work is duplicated up to the last save.
PipelineStatus
Every job has one of five statuses:StorageAdapter
The StorageAdapter is the interface betweencl-pipelines and your database or key-value store. You implement five methods:
SchedulerAdapter
The SchedulerAdapter is the interface betweencl-pipelines and your job queue or task scheduler. It has a single method:
scheduleAdvance(jobId, 0) to trigger the next advance. You implement this by enqueuing a call to advancePhase in your scheduler (e.g. Convex’s ctx.scheduler.runAfter).
RetryMode
RetryMode controls what happens when you callrunPipeline on a job that already has a checkpoint:
When no
retryMode is specified and a checkpoint exists, the library behaves as "resume". See the Retry Modes page for guidance on when to choose each.
PhaseResult
Everyrun function must return one of three result shapes:
Both
{ kind: "error" } returns and thrown exceptions preserve the checkpoint. This means retryMode: "resume" works correctly for all error scenarios — the job can always resume from the last safe state.