Skip to content

Chaining AI Like a Pro

One AI call is nice. But the real magic happens when you chain them together—feeding the output of one model into the input of the next. Think of it as building an assembly line for intelligence.

What You'll Learn

  • How to pass data between multiple AI steps
  • Mixing AI calls with Python processing
  • The three patterns that solve 90% of multi-step problems

Your First Pipeline

Let's build something real: a tool that extracts key points from an article, then turns them into a tweet thread.

name: article-to-tweets
version: "1.0.0"
description: Turn articles into tweet threads

steps:
  # Step 1: Extract the essence
  - type: prompt
    provider: claude
    prompt: |
      Extract 5 key insights from this article.
      Be specific and quotable.

      {input}
    output_var: key_points

  # Step 2: Transform into tweets
  - type: prompt
    provider: claude
    prompt: |
      Turn these insights into a compelling tweet thread.
      Each tweet under 280 characters.
      Make the first tweet a hook.

      Insights:
      {key_points}
    output_var: thread

output: "{thread}"

The magic is in line 20: {key_points} contains the output from Step 1. Data flows downstream automatically.

The Variable Waterfall

Think of variables like water flowing downhill—they only go forward, never back:

📥

Input

{input}

🤖

Step 1

{key_points}

🤖

Step 2

{thread}

📤

Output

Step 2 can use: {input}, {key_points}
Step 2 cannot use: Variables from Step 3 (doesn't exist yet!)

Adding Python Glue

AI is great at language. Python is great at data wrangling. Together? Unstoppable.

name: email-extractor
version: "1.0.0"
description: Extract and deduplicate emails from messy text

steps:
  # AI finds the emails
  - type: prompt
    provider: claude
    prompt: |
      Extract all email addresses from this text.
      Return them comma-separated, nothing else.

      {input}
    output_var: emails_raw

  # Python cleans them up
  - type: code
    code: |
      # Split, clean, deduplicate
      emails = [e.strip().lower() for e in emails_raw.split(',')]
      emails = [e for e in emails if '@' in e and '.' in e]
      unique_emails = sorted(set(emails))
      count = len(unique_emails)
      clean_list = '\n'.join(unique_emails)
    output_var: clean_list, count

  # AI formats the output nicely
  - type: prompt
    provider: claude
    prompt: |
      Format these {count} email addresses as a clean list
      with any obvious categorization (personal, work, etc):

      {clean_list}
    output_var: result

output: "{result}"

Pro Tip: Code Steps Return Multiple Variables

Notice output_var: clean_list, count—you can export multiple variables from a single code step. Just list them comma-separated.

The Three Patterns That Solve Everything

Extract → Transform → Format

prompt  # Pull out data
code    # Clean/filter
prompt  # Make it pretty

Use for: Data extraction, report generation

Analyze → Synthesize

prompt  # Break it down
prompt  # Build it up

Use for: Summaries, insights, rewriting

Validate → Process

code    # Check input
prompt  # Do the work

Use for: Safe processing, error handling

When Things Go Wrong

Warning: Steps Are All-Or-Nothing

If Step 2 fails, Step 3 never runs. Design defensively!

steps:
  # Guard clause in code
  - type: code
    code: |
      if not input.strip():
          processed = "ERROR: Empty input"
          is_valid = False
      else:
          processed = input
          is_valid = True
    output_var: processed, is_valid

  # Only meaningful if valid
  - type: prompt
    provider: claude
    prompt: |
      Summarize this text: {processed}
    output_var: summary

Try It: Build a Code Explainer

Exercise

Build a tool that:

  1. Identifies the programming language
  2. Explains what the code does (using the language info)
  3. Suggests improvements
See the solution
name: code-explainer
version: "1.0.0"
description: Understand and improve any code

steps:
  - type: prompt
    provider: claude
    prompt: |
      What programming language is this?
      Reply with just the language name.

      {input}
    output_var: language

  - type: prompt
    provider: claude
    prompt: |
      Explain this {language} code in plain English.
      Describe what each part does.

      {input}
    output_var: explanation

  - type: prompt
    provider: claude
    prompt: |
      Suggest 3 improvements for this {language} code.
      Consider readability, performance, and best practices.

      Code:
      {input}

      Current understanding:
      {explanation}
    output_var: improvements

output: |
  ## Language: {language}

  ## Explanation
  {explanation}

  ## Suggested Improvements
  {improvements}

Debugging Multi-Step Tools

# See what prompts are being built
cat test.txt | my-tool --dry-run

# Watch each step execute
cat test.txt | my-tool --verbose

# Test with mock provider first
cat test.txt | my-tool --provider mock

Next Up

Ready to go deeper? Learn the full power of code steps: