# Builder API
URL: /docs/workflow/api-reference/builder

workflow(), WorkflowBuilder, and SandboxBuilder — the @alineo-labs/workflow lazy orchestration layer.



```ts
import { workflow, WorkflowBuilder, SandboxBuilder } from "@alineo-labs/workflow";
```

## workflow() [#workflow]

```ts
workflow(client: Sandbox): WorkflowBuilder
```

Creates a `WorkflowBuilder` attached to a `Sandbox` client.

```ts
import { workflow } from "@alineo-labs/workflow";

await workflow(client)
  .sandbox({ image: "node:22", resources: { cpu: "500m", memory: "512Mi" } }, (sb) => {
    sb.exec("npm ci");
    sb.exec("npm test");
  })
  .pipe(process.stdout);
```

## WorkflowBuilder [#workflowbuilder]

Collects stages and executes them all when `.pipe()` or `.result()` is awaited. Sandbox lifecycle (create + close) is managed automatically.

### .sandbox() [#sandbox]

```ts
.sandbox(opts: SandboxOptions, fn: (sb: SandboxBuilder) => void): this
```

Add a sandbox stage. The `fn` callback receives a `SandboxBuilder` to queue operations synchronously. Multiple `.sandbox()` calls run sequentially.

### .parallel() [#parallel]

```ts
.parallel(configs: SandboxOptions[], fn: (sb: SandboxBuilder) => void): this
```

Run the same operation across multiple containers simultaneously. All configs receive the same `fn`. Results are merged.

```ts
await workflow(client)
  .parallel([{ image: "node:20" }, { image: "node:22" }, { image: "node:24" }], (sb) =>
    sb.exec("npm test"),
  )
  .pipe(process.stdout);
```

### .sequence() [#sequence]

```ts
.sequence(steps: SequenceStep[]): this
```

Run sandboxes one after another. Each step's callback receives the previous step's `WorkflowResult` as `prev`:

```ts
await workflow(client)
  .sequence([
    {
      image: "node:22",
      name: "build",
      resources: { cpu: "1", memory: "512Mi" },
      run: (sb) => sb.exec("npm run build"),
    },
    {
      image: "ubuntu:22.04",
      name: "deploy",
      resources: { cpu: "500m", memory: "256Mi" },
      run: (sb, prev) => sb.exec("./deploy.sh"),
    },
  ])
  .pipe(process.stdout);
```

### .pipe() [#pipe]

```ts
await workflow.pipe(writable: { write(chunk: string): unknown }): Promise<void>
```

Execute the workflow and stream stdout to a writable. Flushes all queued stages.

### .result() [#result]

```ts
await workflow.result(): Promise<WorkflowResult>
```

Execute the workflow and return the combined result:

```ts
interface WorkflowResult {
  stdout: string; // concatenated stdout from all sandboxes
  vars: Record<string, unknown>; // values captured by readFile(path, as)
}
```

## SandboxBuilder [#sandboxbuilder]

Queues operations synchronously. All methods return `this` for chaining. Nothing runs until the `WorkflowBuilder` is flushed.

### .exec() [#exec]

```ts
sb.exec(cmd: string, opts?: ExecOptions): this
```

Queue a shell command.

### .execCode() [#execcode]

```ts
sb.execCode(code: string, opts?: ExecCodeOptions): this
```

Queue a code execution via the interpreter.

### .writeFile() [#writefile]

```ts
sb.writeFile(path: string, content: string): this
```

Queue a file write into the sandbox.

### .readFile() [#readfile]

```ts
sb.readFile(path: string, as: string): this
```

Queue a file read. The content is stored in `vars[as]` and available via `WorkflowResult.vars`.

### .moveFile() [#movefile]

```ts
sb.moveFile(from: string, to: string): this
```

Queue a file move inside the sandbox.

### .deleteFile() [#deletefile]

```ts
sb.deleteFile(path: string): this
```

Queue a file deletion.

### .checkpoint() [#checkpoint]

```ts
sb.checkpoint(name?: string): this
```

Queue a container snapshot.

### .retry() [#retry]

```ts
sb.retry(
  maxAttempts: number,
  fn: (sb: SandboxBuilder) => void,
  opts?: RetryOptions,
): this
```

Queue a retry block. Runs up to `maxAttempts` total attempts (the first run plus retries), waiting `delayMs` between each on failure.

```ts
interface RetryOptions {
  delayMs?: number; // default: 1000
  backoff?: "fixed" | "exponential"; // default: "fixed"
}
```

### .when() [#when]

```ts
sb.when(
  pred: (ctx: { stdout: string; exitCode: number; vars: Record<string, unknown> }) => boolean,
  then: (sb: SandboxBuilder) => void,
  otherwise?: (sb: SandboxBuilder) => void,
): this
```

Queue a conditional branch. `pred` is evaluated at flush time with the current execution context.

### .forEach() [#foreach]

```ts
sb.forEach(
  items: unknown[],
  fn: (sb: SandboxBuilder, item: unknown, index: number) => void,
  opts?: ForEachOptions,
): this
```

Queue iteration over a list of items.

```ts
interface ForEachOptions {
  concurrency?: number; // default: 1 (sequential)
}
```
