> ## Documentation Index
> Fetch the complete documentation index at: https://docs.os.meetluno.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Workflow steps

> Run actions as steps inside a workflow.

Inside a [workflow](https://docs.os.meetluno.ai/learn/workflows/overview.md), an [action](https://docs.os.meetluno.ai/learn/actions/overview.md) is a step. You pass the action to the workflow builder with `.then(action)`; the workflow records the result so a retry can skip work that already succeeded. This is the most common way to compose actions, since an action can never call another action directly.

## Use an action as a step

Chain the action onto `defineWorkflow()` with `.then()`. Each step receives the previous step's output as its input (the first step gets the workflow input). The input is validated against the action's `input` schema, and the result is validated against its `output`. Use `.map()` to reshape data between steps, and finish with `.commit()`.

```ts src/workflows/signup-pipeline.ts theme={null}
import { defineWorkflow } from "@meetluno/luno/workflow";
import { z } from "zod";
import { researchSignup } from "../actions/research-signup";
import { postBrief } from "../actions/post-brief";

export default defineWorkflow({
  slug: "signup-pipeline",
  name: "Signup pipeline",
  description: "Researches a signup and posts a brief.",
  input: z.object({ name: z.string(), email: z.string().email() }),
  output: z.object({ ok: z.boolean() }),
})
  .then(researchSignup) // { name, email } -> { brief }
  .map(({ inputData }) => ({ text: inputData.brief }))
  .then(postBrief) // { text } -> { ok }
  .commit();
```

Steps are type-checked: `.then()` rejects an action whose input does not accept the previous output, and `.commit()` is a type error when the last step's output does not match the workflow's `output`. Branches, loops, and parallel steps use `.branch()`, `.foreach()`, `.dowhile()`/`.dountil()`, and `.parallel()`; see [build workflows](https://docs.os.meetluno.ai/learn/workflows/build-workflows.md).

The step id defaults to the action's slug. To use the same action twice in one workflow, give the second use its own id with `.as()`:

```ts theme={null}
.then(postBrief)
.map(({ inputData }) => ({ text: `Follow-up: ${inputData.ok}` }))
.then(postBrief.as("post-follow-up"))
```

## Durability

As each step completes, its result is saved with the run. If a later step fails and the run is retried, it resumes from the failed step: completed steps are not run again.

Two practical consequences:

* **Put side effects inside steps.** Keep network calls and writes inside actions (or other steps) so their results are recorded and not repeated. `.map()` is for pure reshaping, not side effects.
* **Make steps idempotent where you can.** A step can be retried after a transient failure, so design actions to tolerate being called more than once with the same input.

See [durability and retries](https://docs.os.meetluno.ai/learn/workflows/build-workflows.md#durability-and-retries) for the full model.

## Scope credentials per step

When a step's action declares `credentials` that could resolve at more than one [scope](https://docs.os.meetluno.ai/learn/credentials/overview.md), pin the scope with `.scope()`:

```ts theme={null}
.then(postBrief.scope("user"))
```

Without an explicit scope, the resolver uses the project default, then the organization default. Credentials bind to the step (`step:<id>`), so for `.scope("user")`, [assign a user credential](https://docs.os.meetluno.ai/learn/credentials/connect-credentials.md#bind-a-credential-to-a-step-tool-or-poll-action) to that step — user scope is not inferred from the run.

## Actions, agents, and LLM steps

A workflow can mix deterministic action steps with [agent steps](https://docs.os.meetluno.ai/learn/workflows/build-workflows.md#agent-steps) (`agentStep(agent, { prompt })`) and one-shot [LLM steps](https://docs.os.meetluno.ai/learn/workflows/build-workflows.md#llm-steps) (`llmStep(id, { prompt })`). A common shape is to run actions to gather data, prompt an agent to make a decision or draft text, then run more actions to act on the result.

## Next steps

> **[Build workflows](https://docs.os.meetluno.ai/learn/workflows/build-workflows.md)**
>
> Steps, durability, durable waits, and the run context.

> **[Actions as agent tools](https://docs.os.meetluno.ai/learn/actions/agent-tools.md)**
>
> Attach the same actions to an agent as tools.

> **[Test workflows](https://docs.os.meetluno.ai/learn/workflows/test-workflows.md)**
>
> Run a workflow and assert its output.

> **[Workflow runs](https://docs.os.meetluno.ai/learn/logs/workflow-runs.md)**
>
> Inspect each step's input, output, and errors.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.