Gated exit (default)

Prompt Chaining diagramBrief, Outline, Check, Draft, Polish, Post. Step captions follow the diagram.BriefOutlineCheckDraftPolishPostPrompt Chaining diagramBrief, Outline, Check, Draft, Polish, Post. Step captions follow the diagram.BriefOutlineCheckDraftPolishPost

All steps

"Write a post on index tuning"

"Outline is missing sections"

Parts of this pattern
Brief Input / output
The blog-post brief that starts the chain, such as 'Write a post on index tuning for Postgres'.
Outline LLM call
First call: turns the brief into a 4-6 section outline, returned as JSON with a heading and point per section.
Check Guard
Plain code, not a model: checks the outline JSON parses and has the required sections before any drafting.
Draft LLM call
Second call: writes the full post from the approved outline alone, keeping its sections and order.
Polish LLM call
Third call: polishes the draft for tone and clarity and returns the finished post.
Post Input / output
The finished post, or an early exit with the rejected outline when the check fails.
Brief → Outline
The brief is filled into the outline prompt and sent to the first call.You are planning a blog post for backend engineers. <brief>Write a post on index tuning for Postgres</brief>
Outline → Check
The outline JSON goes to the code check instead of straight to the next call.{"sections": [{"heading": "Why indexes matter", "point": "Avoid full scans."}, {"heading": "Reading EXPLAIN", "point": "Find the scan."}, {"heading": "Composite indexes", "point": "Order matters."}, {"heading": "Measuring", "point": "Compare timings."}]}
Check → Draft
A valid outline continues down the chain to the draft step.Write the full post from this approved outline: {"sections": [{"heading": "Why indexes", "point": "Avoid scans."}, {"heading": "EXPLAIN", "point": "Find the scan."}, {"heading": "Composite", "point": "Order matters."}, {"heading": "Measuring", "point": "Compare timings."}]}
Check → Postexit
An outline that fails the check ends the chain early, so no tokens are spent drafting from it.{"error": "outline failed checks", "outline": {"sections": [{"heading": "Intro", "point": "..."}, {"heading": "Tips", "point": "..."}]}}
Draft → Polish
The full draft passes to the last call for a polish pass.Index tuning starts with measurement. Run EXPLAIN ANALYZE on the slow query and look for a Seq Scan on a large table...
Polish → Post
The polished post leaves the chain as its final output.Index Tuning in Postgres: Measure First. Start with EXPLAIN ANALYZE on the slow query and look for sequential scans on large tables...

Gate with retry

A failed check sends its error back to the step that produced the output, for a capped number of retries, instead of ending the chain.

Prompt Chaining: Gate with retry diagramBrief, Outline, Check, Draft, Polish, Post. Step captions follow the diagram.BriefOutlineCheckDraftPolishPostPrompt Chaining: Gate with retry diagramBrief, Outline, Check, Draft, Polish, Post. Step captions follow the diagram.BriefOutlineCheckDraftPolishPost

All steps

Fails once, then passes

Fails every attempt

Parts of this pattern
Brief Input / output
The blog-post brief that starts the chain, such as 'Write a post on index tuning for Postgres'.
Outline LLM call
First call: turns the brief into a 4-6 section outline as JSON; on a retry it also sees the check's error messages.
Check Guard
Plain code, not a model: checks the outline parses and has 4-6 complete sections, and counts the attempts.
Draft LLM call
Second call: writes the full post from the approved outline alone, keeping its sections and order.
Polish LLM call
Third call: polishes the draft for tone and clarity and returns the finished post.
Post Input / output
The finished post, or an error with the last outline once every attempt has failed the check.
Brief → Outline
The brief is filled into the outline prompt and sent to the first call.You are planning a blog post for backend engineers. <brief>Write a post on index tuning for Postgres</brief>
Outline → Check
Each outline goes to the code check before anything is drafted from it.{"sections": [{"heading": "Intro", "point": "Indexes speed reads."}, {"heading": "Tips", "point": "Add indexes."}]}
Check → Outlineretry
A failed check sends its error messages back to the outline step, which tries again while attempts remain.<errors>Outline has 2 sections; it needs 4 to 6.</errors> Attempt 2 of 3.
Check → Draft
A valid outline continues down the chain to the draft step.Write the full post from this approved outline: {"sections": [{"heading": "Why indexes", "point": "Avoid scans."}, {"heading": "EXPLAIN", "point": "Find the scan."}, ...]}
Check → Postgive up
After the last allowed attempt fails, the chain exits with an error instead of drafting.{"error": "outline failed checks after 3 attempts", "errors": ["3 sections, need 4 to 6"]}
Draft → Polish
The full draft passes to the last call for a polish pass.Index tuning starts with measurement. Run EXPLAIN ANALYZE on the slow query and look for a Seq Scan on a large table...
Polish → Post
The polished post leaves the chain as its final output.Index Tuning in Postgres: Measure First. Start with EXPLAIN ANALYZE on the slow query and look for sequential scans on large tables...

Incremental refine

One refine step runs once per chunk of a long input, folding each chunk into a running summary that is carried forward.

Prompt Chaining: Incremental refine diagramBook, Chunker, Refine, Running summary, Summary. Step captions follow the diagram.BookChunkerRefineonce per chunkRunning summarySummaryPrompt Chaining: Incremental refine diagramBook, Chunker, Refine, Running summary, Summary. Step captions follow the diagram.BookChunkerRefineonce perchunkRunningsummarySummary

All steps
Parts of this pattern
Book Input / output
The long input, here a 300-page novel, far too long for one call.
Chunker Tool
Plain code, not a model: splits the book into ordered chunks of about 2,000 tokens, breaking at paragraph ends.
Refine LLM call
One prompt, run once per chunk: it folds the new chunk into the running summary and returns the updated summary.
Running summary Memory
The summary so far, replaced after every chunk; it is the only thing carried from one chunk to the next.
Summary Input / output
The running summary after the last chunk, returned as the book's summary.
Book → Chunker
The whole book goes to the chunker.the-lighthouse-keeper.txt (312 pages, about 95,000 words)
Chunker → Refinechunk i
The chunks go to the refine step one at a time, in order.<part number="3" of="48">Mara rows out to the rock at dawn and finds the lamp already lit...</part>
Refine → Running summary
The refine step's reply replaces the running summary.Mara, the new keeper, arrives on the island and learns the last keeper vanished. On her first morning she finds the lamp lit by someone else.
Running summary → Refineso far
The current summary goes into the next chunk's prompt, so each call sees the story so far without the earlier text.<summary_so_far>Mara, the new keeper, arrives on the island and learns the last keeper vanished.</summary_so_far>
Running summary → Summary
After the last chunk, the running summary is returned as the result.A young keeper on a remote island uncovers why her predecessor vanished, and chooses to stay. 480 words.

← → neighboursesc atlas

Workflows

Prompt Chaining

Also known as Pipeline · Sequential workflow

Break a task into fixed steps, where each LLM call works on the previous output, with optional code checks between steps.

Gated exit, Gate with retry: Popularized by Schluntz & Zhang (2024) · Anthropic

Anthropic named the pattern in 2024. Chaining LLM steps was introduced earlier as AI Chains by Tongshuang Wu, Michael Terry and Carrie J. Cai (University of Washington, Google Research) in 2021: https://arxiv.org/abs/2110.01691.

Incremental refine: No single inventor · see source

Studied, not introduced, by BooookScore (ICLR 2024), which evaluates incremental updating against hierarchical merging for book-length summaries; the workflow was already common in LLM tooling.

Measured over one run

Gated exit

Nodes
6. Boxes in the diagram: models, tools, stores, people and plain code.
LLM calls
3. Model invocations in the first scenario: each time a model or agent node starts thinking, plus each branch it decides.
Tool calls
0. Messages sent to a tool node in the first scenario.
Steps
5. Steps in the first scenario, with repeated steps counted every time they run.
Scenarios
2. Distinct example runs you can switch between on the diagram.
Loop
no. Whether the flow cycles back on itself until a condition is met.
Parallel
no. Whether two or more messages are in flight at the same time.
Branch
yes. Whether the flow takes one path out of several, chosen at run time.
Human in the loop
no. Whether a person appears as a node, to approve, correct or answer.
Autonomy
low. How much the model decides the control flow itself, from fixed code paths (low) to open-ended (high).
Cost
low. Relative token spend per request.
Latency
medium. Relative wall-clock time per request.

Gate with retry

Nodes
6. Boxes in the diagram: models, tools, stores, people and plain code.
LLM calls
4. Model invocations in the first scenario: each time a model or agent node starts thinking, plus each branch it decides.
Tool calls
0. Messages sent to a tool node in the first scenario.
Steps
4. Steps in the first scenario, with repeated steps counted every time they run.
Scenarios
2. Distinct example runs you can switch between on the diagram.
Loop
yes. Whether the flow cycles back on itself until a condition is met.
Parallel
no. Whether two or more messages are in flight at the same time.
Branch
yes. Whether the flow takes one path out of several, chosen at run time.
Human in the loop
no. Whether a person appears as a node, to approve, correct or answer.
Autonomy
low. How much the model decides the control flow itself, from fixed code paths (low) to open-ended (high).
Cost
low. Relative token spend per request.
Latency
medium. Relative wall-clock time per request.

Incremental refine

Nodes
5. Boxes in the diagram: models, tools, stores, people and plain code.
LLM calls
3. Model invocations in the first scenario: each time a model or agent node starts thinking, plus each branch it decides.
Tool calls
1. Messages sent to a tool node in the first scenario.
Steps
5. Steps in the first scenario, with repeated steps counted every time they run.
Scenarios
1. Distinct example runs you can switch between on the diagram.
Loop
yes. Whether the flow cycles back on itself until a condition is met.
Parallel
yes. Whether two or more messages are in flight at the same time.
Branch
no. Whether the flow takes one path out of several, chosen at run time.
Human in the loop
no. Whether a person appears as a node, to approve, correct or answer.
Autonomy
low. How much the model decides the control flow itself, from fixed code paths (low) to open-ended (high).
Cost
low. Relative token spend per request.
Latency
medium. Relative wall-clock time per request.

Counted from the first scenario's timeline when the site is built.

Problem

Some jobs are too big for one prompt to do well. Ask a model to research, outline, draft and polish a blog post in a single call and you get a post that wanders: the structure is an afterthought, and when it is wrong you cannot tell which part went wrong. You want each call to have one narrow job, with a place to catch mistakes before they spread.

How it works

The task is split into a fixed sequence of steps that you choose in advance. A brief goes to the first call, Outline, which produces a structured outline. Its output is the only input to the next stage.

Between steps you can put a programmatic check: ordinary code that confirms the outline is valid JSON, has four to six sections, or stays under a length limit. If the check passes, the chain continues to Draft and then Polish, and the finished post comes out. If it fails, the chain exits early rather than building a draft on a broken outline.

The path never changes. The model fills in each step, but your code decides what the steps are and what order they run in. That is what makes this a workflow rather than an agent.

Two variants change what happens at the edges of that sequence. With a retrying gate, a failed check sends its error back to the step that produced the output, for a capped number of attempts, instead of ending the chain. With incremental refinement, one step runs once per chunk of a long input and carries a running summary forward, which is how a chain summarizes a book that would never fit in one call.

When to use

  • The task splits cleanly into fixed subtasks, such as outline then draft, extract then translate, or generate then format.
  • You are willing to trade latency for accuracy by making each call easier.
  • Intermediate results are worth validating with code before the next call spends tokens on them.

When to avoid

  • The steps cannot be known in advance. If the next step depends on what you find, consider orchestrator-workers or an agent loop.
  • One well-structured prompt already does the job. Extra calls add delay and cost for no gain.
  • The steps are independent of each other and could run side by side, which is sectioning.

Trade-offs

A chain buys accuracy and debuggability at the price of latency: every step waits for the previous one, so three calls take roughly three times as long as one. In return each prompt is short and focused, each intermediate output can be logged and inspected, and a failing step is easy to find and fix. Cost grows linearly with the number of steps, and each step re-reads whatever you pass forward.

Failure modes

  • Errors compound: a subtle mistake in the outline is faithfully expanded into every later step. Put gates early, where mistakes are cheapest to catch.
  • Information loss between steps: the draft only knows what the outline told it. Pass forward everything later steps need, not just the previous answer.
  • Rigid gates: a check that is too strict rejects good output, and one that is too loose lets bad output through. Decide what happens on failure: retry, exit with an error, or hand to a person.
  • Chain bloat: steps accumulate until each does almost nothing. If two steps always change together, merge them.

Build it with your AI

Gated exit

Paste this into Claude Code, Cursor, ChatGPT or any AI coding assistant.

Implement the Prompt Chaining pattern in this codebase, using the LLM client and language we already use.

## Goal

Turn a blog-post brief into a finished post through a fixed sequence of calls (outline, check, draft, polish), stopping early when the outline fails a code check.

## How it works

1. Define the chain in code as an ordered list of steps; each step names its prompt, its input and the one output it passes on. The model never picks the next step.
2. Call the model with the Step 1, outline prompt, filling in the brief and the audience, and parse the reply as JSON into a list of sections.
3. Run the gate in plain code: the JSON parses, it has between 4 and 6 sections, and every section has a non-empty heading and point.
4. If the gate fails, end the chain and return an error result holding the rejected outline and the name of the check that failed. Do not call the draft step.
5. If it passes, call the model with the Step 2, draft prompt, passing only the approved outline and the target word count.
6. Send the draft to a third call that polishes tone and clarity without changing the structure, and return its text as the post.

## Prompts

### Step 1, outline prompt

```markdown
You are planning a blog post for {{audience}}.

<brief>{{brief}}</brief>

Write an outline with 4 to 6 sections. Give each section a heading
and one sentence on what it must prove. Output JSON:
{"sections": [{"heading": "...", "point": "..."}]}
```

### Step 2, draft prompt

```markdown
Write the full post from this approved outline. Follow it exactly:
same sections, same order, no new sections.

<outline>{{outline}}</outline>

Keep to about {{word_count}} words and write in a plain, concrete voice.
```

## Stop rule

The chain ends after the polish step, or at the first failed gate. Nothing loops: each step runs once, so a run makes at most 3 model calls, plus one retry per failed call.

## Requirements

- Keep the section bounds (default 4 to 6) and the word count (default 800) as parameters, not literals inside a prompt.
- If a model call errors or times out, retry it once, then end the chain with an error that names the step.
- Pass each step only the fields it needs, as named values (outline, draft), never the whole conversation so far.
- Log every step's input, output, gate result and token count, so a bad post can be traced to the step that caused it.
- Add a test with a stub LLM whose outline has 2 sections; assert exactly one model call was made and the result is an error containing that outline.

Gate with retry

Paste this into Claude Code, Cursor, ChatGPT or any AI coding assistant.

Implement the Prompt Chaining pattern (Gate with retry variant) in this codebase, using the LLM client and language we already use.

## Goal

Turn a brief into a finished post through fixed steps, where an outline that fails the code check is sent back with the error for a capped number of retries before the chain gives up.

## How it works

1. Define the chain in code as an ordered list of steps: outline, check, draft, polish. The model never picks the next step.
2. Call the model with the Step 1, outline prompt, filling in the brief and the audience, and parse the reply as JSON into a list of sections.
3. Run the gate in plain code: the JSON parses, it has between 4 and 6 sections, and every section has a non-empty heading and point. Collect every failed check as a short error message.
4. If the gate fails and attempts remain, call the outline step again with the same brief plus the error messages, and check the new outline.
5. If the gate passes, call the model with the Step 2, draft prompt, passing only the approved outline and the word count, then polish the draft in a third call and return it.

## Prompts

### Step 1, outline prompt

```markdown
You are planning a blog post for {{audience}}.

<brief>{{brief}}</brief>

{{#if errors}}
Your previous outline failed these checks. Fix every one:
<errors>{{errors}}</errors>
{{/if}}

Write an outline with 4 to 6 sections. Give each section a heading
and one sentence on what it must prove. Output JSON:
{"sections": [{"heading": "...", "point": "..."}]}
```

### Step 2, draft prompt

```markdown
Write the full post from this approved outline. Follow it exactly:
same sections, same order, no new sections.

<outline>{{outline}}</outline>

Keep to about {{word_count}} words and write in a plain, concrete voice.
```

## Stop rule

Stop after the polish step, or when the outline has failed the gate 3 times in total. In that case return an error result with the last outline and every error message, and do not draft.

## Requirements

- Make the attempt cap a parameter (default 3 attempts, so 2 retries); the retry loop must never run without one.
- Send the gate's error messages back verbatim and specifically ("3 sections, need 4 to 6"), never a bare "invalid".
- Treat a reply that is not valid JSON as a gate failure with the parse error as its message, so it uses the same retry path.
- Log each attempt's outline and errors, so a brief that keeps failing can be found and its prompt fixed.
- Add a test with a stub LLM whose first outline has 2 sections and whose second has 4; assert two outline calls, that the second prompt contains the error, and that a post is returned.

Incremental refine

Paste this into Claude Code, Cursor, ChatGPT or any AI coding assistant.

Implement the Prompt Chaining pattern (Incremental refine variant) in this codebase, using the LLM client and language we already use.

## Goal

Summarize a document too long for one call by running a single refine step once per chunk, in order, carrying a running summary forward from chunk to chunk.

## How it works

1. Split the document in code into chunks that fit the context window with room to spare (default 2,000 tokens each), keeping their order and breaking at paragraph ends.
2. Start with an empty running summary.
3. For each chunk in order, call the model with the Refine prompt, passing the chunk, its position (3 of 40) and the running summary, and replace the summary with the reply.
4. If the new summary is longer than the length cap, call the model once with the Compress prompt, and keep the shorter of the two summaries.
5. After the last chunk, return the running summary.

## Prompts

### Refine prompt

```markdown
You are summarizing a long {{document_type}} one part at a time.

<summary_so_far>{{summary}}</summary_so_far>
<part number="{{index}}" of="{{total}}">{{chunk}}</part>

Update the summary so it also covers this part. Keep earlier
points unless this part contradicts them, keep events in order,
and stay under {{max_words}} words. Return only the summary.
```

### Compress prompt

```markdown
Shorten this summary to under {{max_words}} words. Keep events
in order, keep every name the later parts may need, and drop
detail before dropping events. Return only the summary.

<summary>{{summary}}</summary>
```

## Stop rule

Stop after the last chunk has been folded in. The loop runs exactly once per chunk, so the number of calls is fixed by the input's length, plus at most one compression call per chunk.

## Requirements

- Make the chunk size (default 2,000 tokens) and the summary length cap (default 500 words) parameters.
- Process chunks strictly in order; the summary after chunk i must be the only memory passed to chunk i + 1.
- If a refine call errors, retry it once; if it fails again, stop and return the summary so far with the index of the chunk that failed.
- Save the summary after every chunk, so a long run can resume from the last good chunk.
- Add a test with a stub LLM that replies "S" plus the chunk number; feed 3 chunks and assert 3 calls, that call 3 received "S2" as the summary, and that "S3" is returned.

Prompt templates

Gated exit

Step 1, outline prompt
You are planning a blog post for {{audience}}.
<brief>{{brief}}</brief>
Write an outline with 4 to 6 sections. Give each section a heading
and one sentence on what it must prove. Output JSON:
{"sections": [{"heading": "...", "point": "..."}]}
Step 2, draft prompt
Write the full post from this approved outline. Follow it exactly:
same sections, same order, no new sections.
<outline>{{outline}}</outline>
Keep to about {{word_count}} words and write in a plain, concrete voice.

Gate with retry

Step 1, outline prompt
You are planning a blog post for {{audience}}.
<brief>{{brief}}</brief>
{{#if errors}}
Your previous outline failed these checks. Fix every one:
<errors>{{errors}}</errors>
{{/if}}
Write an outline with 4 to 6 sections. Give each section a heading
and one sentence on what it must prove. Output JSON:
{"sections": [{"heading": "...", "point": "..."}]}
Step 2, draft prompt
Write the full post from this approved outline. Follow it exactly:
same sections, same order, no new sections.
<outline>{{outline}}</outline>
Keep to about {{word_count}} words and write in a plain, concrete voice.

Incremental refine

Refine prompt
You are summarizing a long {{document_type}} one part at a time.
<summary_so_far>{{summary}}</summary_so_far>
<part number="{{index}}" of="{{total}}">{{chunk}}</part>
Update the summary so it also covers this part. Keep earlier
points unless this part contradicts them, keep events in order,
and stay under {{max_words}} words. Return only the summary.
Compress prompt
Shorten this summary to under {{max_words}} words. Keep events
in order, keep every name the later parts may need, and drop
detail before dropping events. Return only the summary.
<summary>{{summary}}</summary>

Related patterns

Composes well with:

Sources

  1. Building effective agents (Anthropic, 2024)

From the Agentic Atlas by Joran Kikke · Edit on GitHub · Suggest a correction