ContractSpec docs

OSS-first docs

These docs teach the open system first: contracts, generated surfaces, runtimes, governance, and incremental adoption. Studio shows up as the operating layer on top, not as the source of truth.

AI index

Workflows

A WorkflowSpec orchestrates multi-step processes. It defines the sequence of operations, handles failures with retries and compensation, and provides observability into long-running tasks.

Core concepts

Identifiers

Each workflow has a unique workflowId and a version. This allows you to run multiple versions of the same workflow simultaneously during migrations or A/B tests.

Steps

A workflow is composed of steps. Each step invokes a CapabilitySpec, passes inputs, and receives outputs. Steps can run sequentially or in parallel.

Transitions

Transitions define the flow between steps. They can be conditional (e.g., "if payment succeeds, go to step 3; otherwise, go to step 5") or unconditional.

Retries

If a step fails, the workflow can retry it with exponential backoff. You specify the maximum number of retries and the backoff strategy in the spec.

Compensation

When a workflow fails partway through, compensation steps undo the effects of completed steps (e.g., refunding a payment, releasing a reservation). This ensures consistency even in failure scenarios.

SLAs

You can define Service Level Agreements (SLAs) for each step or the entire workflow. If a step exceeds its SLA, the system can trigger alerts or escalations.

Example WorkflowSpec (TypeScript)

Here's a simplified example of a payment workflow in TypeScript:

For Vercel Workflow and other VM-evaluated runtimes, author workflow specs from @lssm-tech/lib.contracts-spec/workflow/spec rather than the broad workflow barrel.

import { defineWorkflow } from '@lssm-tech/lib.contracts-spec/workflow/spec'; import { ValidatePaymentMethod, ChargePayment, SendEmail } from './specs'; export const PaymentFlow = defineWorkflow({ meta: { key: 'payment.flow', version: '1.0.0', description: 'End-to-end payment processing', owners: ['team-payments'], tags: ['payments'], stability: 'stable', }, steps: [ { id: 'validate-payment', operation: ValidatePaymentMethod, inputs: (ctx, input) => ({ userId: ctx.userId, paymentMethodId: input.paymentMethodId, }), retry: { maxAttempts: 3, backoff: 'exponential', }, onSuccess: 'charge-payment', onFailure: 'notify-user', }, { id: 'charge-payment', operation: ChargePayment, inputs: (ctx, input, steps) => ({ amount: input.amount, paymentMethodId: input.paymentMethodId, }), compensation: 'refund-payment', onSuccess: 'send-receipt', onFailure: 'notify-admin', }, { id: 'send-receipt', operation: SendEmail, inputs: (ctx, input, steps) => ({ to: ctx.userEmail, template: 'payment-receipt', data: steps['charge-payment'].output, }), }, ], sla: { maxDuration: 30000, // milliseconds alertOnBreach: true, }, });

Triggers

Workflows can be triggered in several ways:

  • Manual invocation

    – A user or system calls the workflow via an API endpoint.

  • Event-driven

    – The workflow starts automatically when a specific event occurs (e.g., a new order is created).

  • Scheduled

    – The workflow runs on a cron schedule (e.g., nightly batch processing).

  • Chained

    – One workflow can invoke another as a step.

Monitoring and versioning

ContractSpec automatically instruments workflows with telemetry. You can view:

  • Real-time execution status for each step

  • Historical run data and success/failure rates

  • Latency distributions and SLA compliance

  • Compensation events and retry attempts

When you update a workflow, you increment its version. Running workflows continue on their original version, while new invocations use the latest version. This allows safe, zero-downtime deployments.

Best practices

  • Keep steps idempotent – they should be safe to retry without side effects.

  • Define compensation for any step that modifies external state.

  • Use meaningful step IDs that describe the operation.

  • Set realistic SLAs and monitor them in production.

  • Test failure scenarios locally before deploying.

OSS docscore-modelStart with OSS. Adopt Studio when you want the operating layer.

Why ContractSpec

Keep educational and comparison content reachable without letting it define the primary OSS learning path.