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

# Getting Started with Agent Workflow

> Compose steps into workflows with typed context, portable runtimes, and quality gates

## What is Agent Workflow?

A workflow is a sequence of **steps**. Each step does one thing — calls an LLM, runs a function, invokes an external agent. Steps pass data through a shared **context** (typed key-value pairs). The workflow compiles to a **graph IR** — a pure data structure that decouples definition from execution. Three runtimes are available: `LocalStepRunner` (in-process, zero overhead), `CheckpointingStepRunner` (JDBC crash recovery), and `TemporalStepRunner` (distributed durable execution) — same workflow code, swap a single `@Bean`.

```java theme={null}
Workflow.define("pr-review")
    .step(fetchDiff)
    .then(analyzeDiff)
    .gate(new JudgeGate(jury, 0.8))
        .onPass(postComment)
        .onFail(revise)
    .end()
    .run(event);
```

## Steps

Steps are the building blocks. Each takes input, does work, produces output.

### Deterministic steps

Pure Java — no LLM, no cost:

```java theme={null}
Step<Object, Object> fetchDiff = Step.named("fetch-diff", (ctx, in) -> {
    // Call GitHub API, return the diff as a string
    return gitHub.getPullRequest(in).getDiff();
});
```

### LLM steps

Several flavors depending on what you're calling:

| Step type         | What it wraps                                                                                          | Typical duration |
| ----------------- | ------------------------------------------------------------------------------------------------------ | ---------------- |
| `ChatClientStep`  | Single Spring AI `ChatClient` call                                                                     | Seconds          |
| `ClaudeStep`      | Full Claude CLI agent session (quick scripts, no trace capture)                                        | Minutes          |
| `AgentClientStep` | External agent runtime with [trace capture](/docs/agent-workflow/trace-capture) (Claude, Gemini, etc.) | Minutes          |
| `A2AStep`         | Remote agent via Agent-to-Agent protocol                                                               | Minutes          |

A `ClaudeStep` isn't a single API call — it runs a complete agentic loop internally. The workflow sees it as one step:

```
Workflow
  └── Step: FetchPR          [deterministic — GitHub API call]
  └── Step: AnalyzeDiff      [ClaudeStep — full agent loop internally]
                                  ├── LLM turn 1 → tool call → result
                                  ├── LLM turn 2 → tool call → result
                                  └── LLM turn N → finish
  └── Step: AssembleReport   [deterministic — string formatting]
```

### Creating steps with ChatClientStep

For a single LLM call, `ChatClientStep` wraps a Spring AI `ChatClient`:

```java theme={null}
ChatClient chat = ChatClient.builder(chatModel).build();

Step<Object, Object> write = Step.named("write", (ctx, in) ->
        chat.prompt()
                .user("Write a 3-sentence story about: " + in)
                .call().content());
```

## Context

Steps communicate through `AgentContext` — a typed key-value store that flows through the workflow:

```java theme={null}
// Define typed keys
static final ContextKey<String> DIFF = ContextKey.of("diff", String.class);
static final ContextKey<Double> RISK_SCORE = ContextKey.of("risk-score", Double.class);

// Step reads from context and writes back
Step<Object, Object> assessRisk = Step.named("assess-risk", (ctx, in) -> {
    String diff = ctx.require(DIFF);          // read upstream output
    double score = evaluateRisk(diff);
    // score becomes this step's output, available to downstream steps
    return score;
});
```

The context is immutable — each step gets a snapshot, mutations produce a new instance. Parallel branches receive independent snapshots and merge at join points.

The framework auto-populates `Steps.outputOf("step-name")` after each step, so any downstream step can read any prior step's output by name.

**Sub-workflow context propagation**: when a `Workflow` is used as a step inside another `Workflow`, its internal context mutations propagate back to the parent automatically. All `updateContext()` writes from nested steps are visible to downstream steps in the parent — no workarounds needed.

## Your First Workflow

```java theme={null}
Step<Object, Object> write = Step.named("write", (ctx, in) ->
        chat.prompt()
                .user("Write a 3-sentence story about: " + in)
                .call().content());

Step<Object, Object> editForAudience = Step.named("edit-audience", (ctx, in) ->
        chat.prompt()
                .user("Rewrite for young adults. Return only the story: " + in)
                .call().content());

Step<Object, Object> editForStyle = Step.named("edit-style", (ctx, in) ->
        chat.prompt()
                .user("Rewrite in a humorous style. Return only the story: " + in)
                .call().content());

String result = (String) Workflow.<String, Object>define("novel-creator")
        .step(write)
        .then(editForAudience)
        .then(editForStyle)
        .run("dragons and wizards");
```

Output flows forward: `write` → `editForAudience` → `editForStyle`. Each step's output is the next step's input.

## The Graph IR

The DSL doesn't execute directly — it builds a `WorkflowGraph`. This separation enables:

* **Portable runtimes** — the IR decouples workflow definition from execution. Three runners ship today: `LocalStepRunner`, `CheckpointingStepRunner` (JDBC), and `TemporalStepRunner` (distributed)
* **Tracing** — every step transition is recorded (`TraceRecorder`)
* **Inspection** — the graph is pure data (nodes + edges), not opaque lambdas

Control flow compiles to real graph structure: a branch is 4 nodes + 4 edges; a loop has a back-edge; parallel has fork/join nodes. All visible in traces.

## Prerequisites

* Java 21+
* Spring AI 2.0

```xml theme={null}
<dependency>
    <groupId>io.github.markpollack</groupId>
    <artifactId>workflow-flows</artifactId>
    <version>0.10.0</version>
</dependency>
```

## What's Next

<CardGroup cols={2}>
  <Card title="Step Parameterization" icon="sliders" href="/docs/agent-workflow/parameterization">
    Constructor injection, input chaining, context keys — 4 patterns for getting data into steps
  </Card>

  <Card title="DSL Primitives" icon="code-branch" href="/docs/agent-workflow/choosing-a-pattern">
    10+ composable patterns — branch, loop, parallel, decision, gate, supervisor
  </Card>

  <Card title="Durability" icon="database" href="/docs/agent-workflow/durability">
    Crash recovery, checkpointing, and distributed execution
  </Card>

  <Card title="Complete Examples" icon="flask" href="/docs/agent-workflow/examples">
    9 runnable integration tests validated against GPT-4.1
  </Card>
</CardGroup>
