March 5, 2025
Claude AI Development

Agent Communication Result Passing

When you're orchestrating multiple AI agents to solve complex problems, you quickly realize that agent communication is the nervous system of your entire system. One agent's output becomes another agent's input. And if you're not careful about how that data flows, you'll end up with context windows full of duplicated information, agents that can't parse results, and pipelines that fail mysteriously in the middle.

This article walks you through the practical mechanics of how subagent results flow back to orchestrating sessions, how to structure output for machine-readability, and how to chain multiple agents together without losing your mind—or your token budget.

Table of Contents
  1. The Core Problem: What Happens When Agents Talk?
  2. How Subagent Results Flow Back
  3. The Text Return Model
  4. Why Text Return? Why Not Direct Object Passing?
  5. Structured Output Patterns: Making Results Machine-Readable
  6. The Standard Result Format
  7. Why This Format Matters
  8. Passing Context Between Agents in Sequential Workflows
  9. The Sequential Pipeline Pattern
  10. Why File Paths, Not Full Text?
  11. The File-Based Communication Pattern
  12. Structured Data Format: YAML vs. JSON vs. CSV
  13. JSON for Complex, Nested Data
  14. YAML for Human-Readable Config and Outlines
  15. CSV for Tabular Data
  16. The Hybrid Pattern
  17. Error Propagation and Handling Failed Results
  18. The FAILED Pattern
  19. Parsing Failures in Bash
  20. Cascading Failures and Checkpoints
  21. Practical Example: A Complete Content Pipeline
  22. Common Pitfalls and How to Avoid Them
  23. Pitfall 1: Copy-Pasting Results Into Prompts
  24. Pitfall 2: No Error Checking
  25. Pitfall 3: Unstructured Outputs
  26. Pitfall 4: No Checkpointing
  27. Pitfall 5: Unclear File Ownership
  28. The Flow Pattern: From Theory to Practice
  29. The Human Cost of Poor Agent Communication
  30. Scaling Beyond Your First Agent Chain
  31. Real-World Failure Modes and Recovery
  32. Memory and Context Windows in Long Pipelines
  33. Building Organizational Alignment Around Agent Communication
  34. Debugging Agent Communication Failures
  35. The Debugging Workflow in Practice
  36. Monitoring and Observability Through Communication Patterns
  37. Evolving Communication Patterns as Systems Grow
  38. Summary

The Core Problem: What Happens When Agents Talk?

Let's paint a realistic scenario. You've built a system where:

  1. Agent A (research-validator) searches for information about a topic
  2. Agent B (content-synthesizer) takes that research and creates a draft
  3. Agent C (editor) refines the draft and fact-checks it

Sounds straightforward, right? But here's what actually happens if you're not careful:

  • Agent A returns its findings as raw text—maybe 2,000 words of research notes mixed with search results and tangential thoughts.
  • You (the orchestrator) copy all 2,000 words into the prompt for Agent B.
  • Agent B struggles to extract the relevant information from the noise. It uses 30% of its context window just to figure out what matters.
  • Agent B returns a 3,000-word draft, which you then paste into the prompt for Agent C.
  • By the time Agent C is running, you've already consumed 5,000+ tokens just passing data back and forth.
  • Nobody's happy. Your costs are exploding. And latency is brutal.

The solution? Structured output patterns and file-based communication. Let's dive into how this actually works and why it transforms your system from chaotic to professional.

How Subagent Results Flow Back

When you dispatch a subagent in Claude Code, here's what happens under the hood:

bash
# You: Invoke a subagent
/dispatch research-validator "Find information about quantum computing"
 
# Claude Code internally:
# 1. Creates a new isolated session context for the subagent
# 2. Runs the agent with its specialized prompts and instructions
# 3. The agent generates text output
# 4. Returns result as TEXT back to the parent session

Key insight: Subagent results come back as plain text strings to your orchestrating session. This is crucial to understand because it shapes everything that follows.

Understanding this model prevents a common misconception: agents can't directly pass objects or memory structures. They generate text, you parse that text, you extract data, and you use that data for the next step. This constraint is actually a feature — it forces clarity and makes systems reproducible and debuggable.

The Text Return Model

When a subagent finishes, you get back whatever it generated—typically one of these patterns:

✓ SUCCESS: Found 47 sources on quantum computing.
Located in: /memory/research/quantum-2026-03-16.json

Research synthesis:
- Quantum entanglement fundamentals (8 sources)
- Error correction advances (12 sources)
- Commercial applications (11 sources)
- Hybrid classical-quantum systems (16 sources)

Notice the structure here:

  • Status indicator (✓ SUCCESS or ✗ FAILED)
  • Summary statement
  • Artifact locations (file paths)
  • Structured breakdown (bullet points with categories)

This pattern is deliberate. It's designed so that:

  1. You (or another agent) can quickly parse whether the agent succeeded
  2. You know exactly where to find the detailed results
  3. The raw details are isolated to files, not pasted into the message

Why is this different from just dumping all the text? Because scalability. When you have 10 agents in a pipeline, if each one returns 2,000 words of raw output and you copy that all into the next prompt, you're burning through token budgets and creating context bloat.

Why Text Return? Why Not Direct Object Passing?

You might ask: "Why not just return a JSON object or a data structure directly?"

Good question. Here are the practical reasons:

  1. Token efficiency: Agents are running in separate sessions. They can't magically hand you Python objects. They have to serialize everything to text. But you can be smart about what text you pass along — you pass file paths, not entire documents.

  2. Portability: Text results work across any tool integration—bash scripts, file I/O, API calls, web browsers. JSON works everywhere. Python objects don't. You want your system to work whether the orchestrator is running in Node.js, Python, bash, or even a spreadsheet formula.

  3. Human readability: You (and future you) need to understand what happened when you look at logs or debug output. If Agent A writes a 2,000-word research document, you need to be able to read it and see what actually happened, not just parse a cryptic data structure.

  4. Flexibility: An agent might return success with warnings, partial results, or structured fallback data. Text lets you express nuance. You can say "Completed, but found 3 conflicting sources" in a way that a rigid data structure can't.

So the pattern is: agents generate text → you parse that text → you extract file paths → you read the files for detailed data. This creates what we call "smart referencing" — instead of copying data, you reference it.

Structured Output Patterns: Making Results Machine-Readable

Now here's where discipline pays off. If every agent returns output in a different format, you're back to chaos. Instead, you define a standard result schema that all your agents follow.

The Standard Result Format

Here's a battle-tested format used in production Claude Code systems:

[STATUS] [AGENT-NAME]: [SHORT-DESCRIPTION]

[METADATA]
Location: [file-path-or-url]
Timestamp: [ISO8601]
Confidence: [HIGH|MEDIUM|LOW]
Completeness: [percentage]

[SUMMARY]
[2-3 sentences of what was accomplished]

[STRUCTURED-DATA]
- Category 1: [description] (count/metric)
- Category 2: [description] (count/metric)

[ARTIFACTS]
Output file: /path/to/detailed-results.json
Fallback data: [inline JSON or CSV if small]

[WARNINGS] (if applicable)
- Warning 1
- Warning 2

Let's see this in practice. Imagine a fact-checker agent runs and returns:

✓ FACT-CHECKER: 12 claims verified from article draft

Location: /workspace/fact-check-report-2026-03-16.json
Timestamp: 2026-03-16T14:23:41Z
Confidence: HIGH
Completeness: 100%

SUMMARY
Reviewed 12 factual claims in the draft. 11 verified against authoritative sources. 1 requires revision (see details).

FACTS VERIFIED
- Climate science claims: 4 verified
- Economic statistics: 3 verified
- Historical events: 4 verified
- Claims requiring revision: 1

ARTIFACTS
Output file: /workspace/fact-check-report-2026-03-16.json
Flag: "economics-2025-gdp-data-outdated"

WARNINGS
- 2025 GDP figure is from preliminary estimates; author should add 2026 official figure

Now, when you (the orchestrator) read this result, you can:

  1. Quick status check: ✓ FACT-CHECKER → OK, it succeeded
  2. Parse the metadata: HIGH confidence, 100% complete
  3. Find the file: /workspace/fact-check-report-2026-03-16.json
  4. Know what to do next: One claim needs revision; agent flagged it with economics-2025-gdp-data-outdated

This is infinitely better than trying to parse free-form text. You've turned a wall of words into a machine-parseable structure.

Why This Format Matters

Structured output enables automated parsing. In your orchestrator script, you can write:

bash
# Parse agent result
result=$(dispatch fact-checker "Check article draft")
 
# Extract status
if [[ $result =~\ FACT-CHECKER ]]; then
    echo "✓ Fact check passed"
else
    echo "✗ Fact check failed"
    exit 1
fi
 
# Extract file path
if [[ $result =~ Location:\ ([^ ]+) ]]; then
    report_file="${BASH_REMATCH[1]}"
    echo "Reading detailed report from $report_file"
    cat "$report_file" | jq '.'
fi

See what we did? We went from "hope the agent's output makes sense" to "reliably parse the result and take action". That's professional infrastructure. You've moved from hope-based systems to verify-based systems.

Passing Context Between Agents in Sequential Workflows

Now let's tackle the core problem: chaining agents together without losing your mind or your context window.

The Sequential Pipeline Pattern

Imagine you're building a content creation pipeline:

[1. Researcher] → [2. Outliner] → [3. Writer] → [4. Editor] → [5. Publisher]

Each agent takes the previous agent's output and builds on it. The naive approach copies everything. The smart approach? Pass references.

Here's how to set this up properly:

bash
#!/bin/bash
# pipeline.sh - Content creation workflow
 
WORKSPACE="/workspace/content-pipeline-$(date +%Y-%m-%d)"
mkdir -p "$WORKSPACE"
 
# ============================================
# STAGE 1: Research
# ============================================
echo "[1/5] Running researcher agent..."
research_result=$(dispatch researcher \
  "Research the topic: 'AI safety alignment challenges'")
 
# Extract research file path
if [[ $research_result =~ Location:\ ([^ ]+) ]]; then
    research_file="${BASH_REMATCH[1]}"
    echo "✓ Research saved to: $research_file"
else
    echo "✗ Research agent failed"
    exit 1
fi
 
# ============================================
# STAGE 2: Outline
# ============================================
echo "[2/5] Running outliner agent..."
# KEY: Pass the research file path to the outliner
outline_result=$(dispatch outliner \
  "Create outline for article. Research available at: $research_file")
 
if [[ $outline_result =~ Location:\ ([^ ]+) ]]; then
    outline_file="${BASH_REMATCH[1]}"
    echo "✓ Outline saved to: $outline_file"
else
    echo "✗ Outline agent failed"
    exit 1
fi
 
# ============================================
# STAGE 3: Writing
# ============================================
echo "[3/5] Running writer agent..."
# KEY: Pass BOTH the outline and research file paths
write_result=$(dispatch writer \
  "Write article following outline at: $outline_file. Reference research at: $research_file")
 
if [[ $write_result =~ Location:\ ([^ ]+) ]]; then
    draft_file="${BASH_REMATCH[1]}"
    echo "✓ Draft written to: $draft_file"
else
    echo "✗ Writer agent failed"
    exit 1
fi
 
# ============================================
# STAGE 4: Editing
# ============================================
echo "[4/5] Running editor agent..."
edit_result=$(dispatch editor \
  "Edit and refine draft at: $draft_file. Verify against research at: $research_file")
 
if [[ $edit_result =~ Location:\ ([^ ]+) ]]; then
    final_file="${EDIT_REMATCH[1]}"
    echo "✓ Final draft saved to: $final_file"
else
    echo "✗ Editor agent failed"
    exit 1
fi
 
# ============================================
# STAGE 5: Summary
# ============================================
echo "[5/5] Pipeline complete!"
echo "Final output: $final_file"
wc -w "$final_file"  # Word count

Critical pattern here: Each agent receives a file path to the previous agent's work, not the entire text pasted into the prompt. This is the difference between a system that scales and one that collapses under its own context weight.

Why File Paths, Not Full Text?

Let's think about the token cost:

  • Research results: 2,000 words → ~500 tokens
  • Outline: 500 words → ~125 tokens
  • Draft: 3,000 words → ~750 tokens

If you paste all three into the editor's prompt, that's 1,375 tokens just for context data. Plus the system prompt, metadata, etc. You're looking at 2,000+ tokens spent on data passing, leaving your 100k context window with less room for actual reasoning.

If you instead pass file paths and let the editor read what it needs:

  • Editor loads the draft (~750 tokens)
  • Editor spot-checks key claims against research (~200 tokens on demand)
  • Total: ~950 tokens

You saved 425 tokens—and more importantly, you kept the editor focused on editing, not drowning in irrelevant research notes. The agent can choose what to read based on what it actually needs, not everything you copy-pasted.

The File-Based Communication Pattern

Here's the principle: Large data lives in files. References to that data flow in prompts.

Agent A ──[writes]──> /workspace/results-a.json
                           ↓
Prompt for Agent B ──> "Results from Agent A available at /workspace/results-a.json"
                           ↓
Agent B ──[reads]──> /workspace/results-a.json
Agent B ──[writes]──> /workspace/results-b.json

This keeps your prompts lean and your file system organized. You're building a file-based knowledge base instead of a context-based one.

Structured Data Format: YAML vs. JSON vs. CSV

Now, what format should agents write to disk?

JSON for Complex, Nested Data

Use JSON when data has relationships or hierarchies:

json
{
  "metadata": {
    "agent": "fact-checker",
    "timestamp": "2026-03-16T14:23:41Z",
    "completeness": 100
  },
  "results": {
    "verified_claims": 11,
    "claims_requiring_revision": 1,
    "confidence": "HIGH"
  },
  "details": [
    {
      "claim_id": "economics-2025-gdp",
      "text": "Global GDP grew 2.3% in 2025",
      "status": "REVISION_REQUIRED",
      "issue": "Uses preliminary estimate; official 2026 figure now available",
      "source": "IMF World Economic Outlook Jan 2026"
    }
  ]
}

JSON is machine-readable and parseable from bash, Python, Node.js—anywhere. It's the most portable format for structured data.

YAML for Human-Readable Config and Outlines

Use YAML for outlines, configs, and narrative structures:

yaml
article:
  title: "AI Safety Alignment Challenges"
  target_audience: "intermediate AI practitioners"
  tone: "educational, balanced"
 
sections:
  - section_id: 1
    title: "The Alignment Problem Defined"
    word_count_target: 800
    key_points:
      - Define AI alignment at a high level
      - Distinguish alignment from safety
      - Explain why it matters
    references:
      - research_tag: "alignment-basics"
      - research_tag: "alignment-importance"
 
  - section_id: 2
    title: "Current Technical Approaches"
    word_count_target: 1200
    key_points:
      - RLHF (Reinforcement Learning from Human Feedback)
      - Constitutional AI
      - Mechanistic interpretability
    references:
      - research_tag: "rlhf-methods"
      - research_tag: "constitutional-ai"

YAML is readable by humans and parseable by scripts, and it handles comments naturally. When an outline is also legible to humans, they can work on it directly if needed.

CSV for Tabular Data

Use CSV for fact lists, comparisons, or structured tables:

csv
claim_id,text,status,confidence,source,date_verified
economics-2025-gdp,"Global GDP growth 2.3% in 2025",REVISION_REQUIRED,HIGH,"IMF WEO Jan 2026",2026-03-16
climate-2025-temp,"Global temperature rose 0.8C above pre-industrial",VERIFIED,HIGH,"IPCC AR6 Synthesis",2026-03-16
tech-ai-cap,"AI compute spending doubled YoY",VERIFIED,MEDIUM,"Compute trends analysis",2026-03-15

CSV works well for fact-checking reports, comparison matrices, and anything tabular. It's also the easiest format to import into spreadsheets if a human needs to review or edit results.

The Hybrid Pattern

Smart agents use a hybrid: JSON for structure, with references to external files:

json
{
  "report_type": "article_review",
  "summary": "Complete draft review with 3 major suggestions",
  "sections_reviewed": 5,
  "overall_rating": 4.2,
  "detailed_feedback": "/workspace/detailed-review.md",
  "inline_suggestions": [
    {
      "section": 2,
      "line": 45,
      "issue": "Sentence is passive voice",
      "suggestion": "Rewrite in active voice"
    }
  ]
}

This gives you quick stats in the JSON, but detailed feedback in a separate file that the writer can review. You've optimized for both machine parsing (the JSON) and human reading (the separate file).

Error Propagation and Handling Failed Results

Here's the reality: agents fail. Networks fail. Data is corrupted. Your pipeline needs to handle this gracefully.

The FAILED Pattern

When an agent hits an error, it should return a structured failure, not a crash:

✗ WRITER: Could not generate article

Location: /workspace/error-log-2026-03-16.json
Timestamp: 2026-03-16T14:45:22Z
Confidence: N/A
Completeness: 0%

SUMMARY
Outline file at /workspace/outline-old.json was not found or corrupted. Cannot proceed without outline.

ERROR DETAILS
Error code: FILE_NOT_FOUND
File path: /workspace/outline-old.json
Attempted action: Read and parse outline JSON

REMEDIATION
- Verify outline was created by previous agent
- Check file permissions
- Re-run outliner agent

Notice the structure—it's the same format, but with ERROR instead of SUCCESS. This makes parsing consistent. Your orchestrator can use the same regex patterns to extract status whether the result succeeded or failed.

Parsing Failures in Bash

Here's how to handle failures in your orchestrator:

bash
#!/bin/bash
 
run_with_retry() {
    local agent=$1
    local prompt=$2
    local max_attempts=3
    local attempt=1
 
    while [ $attempt -le $max_attempts ]; do
        echo "[Attempt $attempt/$max_attempts] Running $agent..."
        result=$(dispatch "$agent" "$prompt")
 
        # Check for success
        if [[ $result =~ ^✓ ]]; then
            echo "$result"
            return 0
        fi
 
        # Check for failure
        if [[ $result =~ ^✗ ]]; then
            echo "✗ Agent failed: $agent"
            echo "$result"
 
            # Only retry if error is transient
            if [[ $result =~ "TRANSIENT" ]] && [ $attempt -lt $max_attempts ]; then
                echo "Retrying in 5 seconds..."
                sleep 5
                ((attempt++))
            else
                # Permanent error, bail out
                return 1
            fi
        fi
    done
 
    return 1
}
 
# Use it
if ! run_with_retry researcher "Research topic X"; then
    echo "✗ Pipeline failed at research stage"
    exit 1
fi

This gives you retry logic for transient failures, but fails fast on permanent errors. You're not wasting token budget on retrying something that will never work.

Cascading Failures and Checkpoints

For long pipelines, consider checkpoints:

bash
#!/bin/bash
 
CHECKPOINT_DIR="/workspace/checkpoints"
mkdir -p "$CHECKPOINT_DIR"
 
# Checkpoint function
checkpoint() {
    local stage=$1
    local result=$2
    local file="$CHECKPOINT_DIR/$stage.json"
 
    echo "Saving checkpoint: $stage"
    echo "$result" > "$file"
    echo "  Path: $file"
}
 
# Restore function
restore_checkpoint() {
    local stage=$1
    local file="$CHECKPOINT_DIR/$stage.json"
 
    if [ -f "$file" ]; then
        cat "$file"
        return 0
    else
        return 1
    fi
}
 
# Pipeline with checkpoints
if result=$(restore_checkpoint "research"); then
    echo "✓ Restored research from checkpoint"
    research_result="$result"
else
    echo "Running research (no checkpoint)..."
    research_result=$(dispatch researcher "Research topic X")
    checkpoint "research" "$research_result"
fi
 
# Continue with outline, writer, etc.
# Each stage saves a checkpoint

This way, if the editor fails, you can re-run just the editor without re-running the entire pipeline. You've saved hours of token budget and wall-clock time. Checkpointing transforms your pipeline from "restart from the beginning" to "resume from the failure point."

Practical Example: A Complete Content Pipeline

Let's build a real, working example. We're creating a technical article with:

  1. Research phase: Gather sources
  2. Outline phase: Structure the article
  3. Writing phase: Generate draft
  4. Fact-check phase: Verify claims
  5. Polish phase: Final edits
  6. Publish phase: Format and export
bash
#!/bin/bash
# article-pipeline.sh
# Complete content creation pipeline with error handling
 
set -e  # Exit on any error
 
# ============================================
# CONFIGURATION
# ============================================
WORKSPACE="/workspace/article-$(date +%Y%m%d-%H%M%S)"
ARTICLE_TOPIC="Claude Code agent communication patterns"
TARGET_WORDS=3500
 
mkdir -p "$WORKSPACE"
echo "Pipeline workspace: $WORKSPACE"
 
# ============================================
# HELPER: Parse agent result
# ============================================
parse_result() {
    local result=$1
 
    # Extract status
    if [[ $result =~ ^✓ ]]; then
        echo "status=success"
    elif [[ $result =~ ^✗ ]]; then
        echo "status=failed"
    else
        echo "status=unknown"
    fi
 
    # Extract file location
    if [[ $result =~ Location:\ ([^ ]+) ]]; then
        echo "file=${BASH_REMATCH[1]}"
    fi
}
 
# ============================================
# STAGE 1: RESEARCH
# ============================================
echo ""
echo "=== STAGE 1: Research ==="
 
research_result=$(dispatch research-validator \
  "Research: $ARTICLE_TOPIC
 
   Find:
   - Best practices for agent communication
   - Real-world examples of agent pipelines
   - Common pitfalls and failures
   - Technical patterns and architectures
 
   Target: 15-20 quality sources, structured summary")
 
# Evaluate result
eval $(parse_result "$research_result")
 
if [ "$status" = "failed" ]; then
    echo "✗ Research stage failed"
    exit 1
fi
 
echo "✓ Research complete"
echo "  File: $file"
research_file="$file"
 
# ============================================
# STAGE 2: OUTLINE
# ============================================
echo ""
echo "=== STAGE 2: Outline ==="
 
outline_result=$(dispatch story-architect \
  "Create detailed outline for article: $ARTICLE_TOPIC
 
   Use research from: $research_file
 
   Structure:
   - Introduction (hook + problem statement)
   - 4-5 main sections (each ~700 words)
   - Practical examples with code
   - Common pitfalls
   - Summary
 
   Target: ~3,500 words total
   Format: YAML with section details, word count targets, key points")
 
eval $(parse_result "$outline_result")
 
if [ "$status" = "failed" ]; then
    echo "✗ Outline stage failed"
    exit 1
fi
 
echo "✓ Outline complete"
echo "  File: $file"
outline_file="$file"
 
# ============================================
# STAGE 3: WRITING
# ============================================
echo ""
echo "=== STAGE 3: Writing ==="
 
write_result=$(dispatch prose-generator \
  "Write article following outline and research.
 
   Outline: $outline_file
   Research: $research_file
   Topic: $ARTICLE_TOPIC
 
   Requirements:
   - Voice: conversational, authoritative, casual interjections
   - Use H2/H3 headers
   - Short paragraphs
   - Code examples with explanations
   - Explain the WHY
   - Address common pitfalls
   - Bold key terms
   - Target: 3,500+ words
   - Format: Markdown
   - Include code in bash
 
   Tone examples:
   'When you're orchestrating multiple AI agents...'
   'Here's the practical reality...'
   'Let me show you what actually happens...'")
 
eval $(parse_result "$write_result")
 
if [ "$status" = "failed" ]; then
    echo "✗ Writing stage failed"
    exit 1
fi
 
echo "✓ Draft written"
echo "  File: $file"
draft_file="$file"
 
# Verify word count
word_count=$(wc -w < "$draft_file")
echo "  Word count: $word_count (target: $TARGET_WORDS+)"
 
if [ $word_count -lt $TARGET_WORDS ]; then
    echo "⚠ Warning: Draft below target word count"
fi
 
# ============================================
# STAGE 4: FACT-CHECK
# ============================================
echo ""
echo "=== STAGE 4: Fact-Check ==="
 
check_result=$(dispatch research-validator \
  "Fact-check article draft.
 
   Draft: $draft_file
   Research: $research_file
 
   Verify:
   - All claims are supported by research
   - No outdated information
   - Examples are technically accurate
   - Citations are accurate
 
   Format output as JSON with:
   - verified_claims (count)
   - claims_needing_revision (list with details)
   - overall_confidence (HIGH/MEDIUM/LOW)")
 
eval $(parse_result "$check_result")
 
if [ "$status" = "failed" ]; then
    echo "✗ Fact-check stage failed"
    exit 1
fi
 
echo "✓ Fact-check complete"
echo "  File: $file"
check_file="$file"
 
# ============================================
# STAGE 5: POLISH
# ============================================
echo ""
echo "=== STAGE 5: Polish & Edit ==="
 
polish_result=$(dispatch style-enforcer \
  "Polish and refine article draft.
 
   Draft: $draft_file
   Fact-check: $check_file
 
   Tasks:
   - Address all fact-check flags
   - Improve clarity and flow
   - Strengthen transitions
   - Optimize pacing (avoid long sections)
   - Ensure consistent voice
   - Check for filter words to remove
   - Verify code examples run correctly
   - Add inline explanations after code blocks
 
   Format: Return polished markdown, ready for publication")
 
eval $(parse_result "$polish_result")
 
if [ "$status" = "failed" ]; then
    echo "✗ Polish stage failed"
    exit 1
fi
 
echo "✓ Polish complete"
echo "  File: $file"
final_file="$file"
 
# ============================================
# FINAL SUMMARY
# ============================================
echo ""
echo "=== PIPELINE COMPLETE ==="
echo ""
echo "Article: $ARTICLE_TOPIC"
echo "Final output: $final_file"
echo "Word count: $(wc -w < "$final_file") words"
echo "Workspace: $WORKSPACE"
echo ""
echo "All files:"
ls -lh "$WORKSPACE"
echo ""
echo "✓ Ready for publication!"

Run this with:

bash
chmod +x article-pipeline.sh
./article-pipeline.sh

Each stage reads from the previous stage's output file. Errors stop the pipeline immediately. The final result is a polished, fact-checked article. You've gone from a manual, error-prone process to an automated, resilient pipeline.

Common Pitfalls and How to Avoid Them

Pitfall 1: Copy-Pasting Results Into Prompts

Problem: You get a 2,000-word research result and paste it into the next agent's prompt.

bash
# ✗ DON'T DO THIS
research=$(dispatch researcher "Research X")
write=$(dispatch writer "Write article. Here's the research: $research")

Why it's bad:

  • Token waste (entire text becomes context)
  • Agent gets distracted by noise (signal-to-noise ratio is awful)
  • Harder to iterate independently (change research, re-run writer)
  • Unmaintainable (where does the research file live? nobody knows)

Solution: Use file paths

bash
# ✓ DO THIS
research_result=$(dispatch researcher "Research X")
if [[ $research_result =~ Location:\ ([^ ]+) ]]; then
    research_file="${BASH_REMATCH[1]}"
    write=$(dispatch writer "Write article using research at: $research_file")
fi

Pitfall 2: No Error Checking

Problem: Agent fails silently; you don't notice until stage 5.

bash
# ✗ DON'T DO THIS
result=$(dispatch writer "Write article")
next_result=$(dispatch editor "Edit $result")  # What if $result is an error?

Solution: Check for status explicitly

bash
# ✓ DO THIS
result=$(dispatch writer "Write article")
if [[ ! $result =~ ^✓ ]]; then
    echo "Writer failed: $result"
    exit 1
fi

Pitfall 3: Unstructured Outputs

Problem: Agents return free-form text. You spend hours parsing it.

Solution: Define a result schema and enforce it

bash
# In your agent's system prompt:
# "Always return results in this format:
#  ✓ AGENT-NAME: [summary]
#  Location: [file path]
#  Timestamp: [ISO8601]
#  [Details]"

Pitfall 4: No Checkpointing

Problem: A 20-stage pipeline fails at stage 19. You re-run everything.

Solution: Checkpoint after each stage

bash
checkpoint() {
    local stage=$1
    local result=$2
    cp "$result" "/checkpoints/$stage.json"
}
 
# Then later:
if [ -f "/checkpoints/stage-14.json" ]; then
    echo "Resuming from stage 15..."
    # Continue from there
fi

Pitfall 5: Unclear File Ownership

Problem: Three agents write to /workspace/results.json. They overwrite each other.

Solution: Include agent name and timestamp in filenames

bash
# ✓ Unique filenames
/workspace/research-2026-03-16-14-23.json
/workspace/outline-2026-03-16-14-25.json
/workspace/draft-2026-03-16-14-45.json

Each agent creates its own uniquely-named file. No collisions, clear lineage, easy debugging.

The Flow Pattern: From Theory to Practice

Let's map out the complete flow one more time:

┌─────────────────────────────────────────────────────────────┐
│ Orchestrator (parent session)                               │
│                                                             │
│  1. Dispatch Agent A with prompt P1                         │
└─────────────────────────────────────────────────────────────┘
            │
            ↓ (sends P1 to Agent A's isolated session)

┌─────────────────────────────────────────────────────────────┐
│ Agent A Session (isolated context)                          │
│                                                             │
│  - Reads custom prompts for Agent A                         │
│  - Processes prompt P1                                      │
│  - Generates response                                       │
│  - Writes detailed results to disk: /workspace/result-a.json│
│  - Returns structured text with file path                   │
└─────────────────────────────────────────────────────────────┘
            │
            ↓ (returns: "✓ AGENT-A: ... Location: /workspace/result-a.json")

┌─────────────────────────────────────────────────────────────┐
│ Orchestrator (parent session)                               │
│                                                             │
│  2. Parse result → extract file path                        │
│  3. Read detailed results from /workspace/result-a.json     │
│  4. Create prompt P2 including file path (not full text)    │
│  5. Dispatch Agent B with prompt P2                         │
└─────────────────────────────────────────────────────────────┘
            │
            ↓ (sends P2 to Agent B's isolated session)

┌─────────────────────────────────────────────────────────────┐
│ Agent B Session (isolated context)                          │
│                                                             │
│  - Reads custom prompts for Agent B                         │
│  - Processes prompt P2 (which references /workspace/result-a.json)
│  - Can read /workspace/result-a.json if needed             │
│  - Generates response                                       │
│  - Writes results to disk: /workspace/result-b.json        │
│  - Returns structured text with file path                   │
└─────────────────────────────────────────────────────────────┘
            │
            ↓ (continues to Agent C, D, E...)

Each agent:

  • Has isolated session context (won't bloat main context window)
  • Writes structured results to disk
  • Returns a summary + file path
  • Doesn't send multi-thousand-word blobs back to the orchestrator

This design enables:

  • Scalability: You can add 100 agents without burning through tokens
  • Debuggability: Every intermediate artifact is saved and timestamped
  • Resilience: Failures are isolated; checkpoints let you resume
  • Efficiency: Agents only load data they actually need

The Human Cost of Poor Agent Communication

Understanding why agent communication patterns matter requires stepping back from the technical details. When systems fail because agents can't communicate effectively, the human cost compounds quickly. A miscommunicated research finding cascades into a poorly written article. A parsing error in one agent's output causes the next agent to make completely wrong assumptions. What started as a minor communication hiccup becomes a pipeline that produces garbage, wastes token budgets, burns through API quotas, and requires manual salvage operations.

I've seen teams burn through thousands of tokens trying to debug why a chain of five agents produced nonsensical output. The culprit was always the same: agent A returned its findings in one format, agent B expected a different structure, and agent C had to work from corrupted data. Nobody caught it because there was no validation at the communication boundaries.

The tragedy of poor communication patterns is that they compound at scale. You might think one agent miscommunication is isolated. It's not. When you have a five-stage pipeline where each stage assumes the previous stage's output format without verification, a single formatting mistake at stage 1 cascades through all five stages. By stage 5, you're working with completely corrupted data but you're three hours into processing before you realize something went wrong. Then you have to trace backwards through all five stages to find where the corruption occurred. What took minutes to prevent now takes days to debug and fix.

The cost goes beyond just wasted processing time. There's the opportunity cost of agents not working on other problems. There's the cognitive load on engineers who have to understand five different agents' output formats. There's the risk of deploying agent output without validation, only to discover later that the data was corrupt. There's the morale hit when developers realize they can't trust the agent pipeline because it produces garbage.

When you implement proper communication patterns—structured output, file-based references, explicit status indicators—you eliminate entire categories of failures. Errors become visible and debuggable at the moment they occur, not hours later when downstream agents fail mysteriously. You can trace exactly where communication broke down because every handoff is logged and tracked. You know which agent failed, why, and what data it was processing when it failed.

This fundamentally changes how you approach agent orchestration. Instead of hope-based systems ("I hope the agents communicate properly"), you build verify-based systems where every handoff is validated. The validation overhead is minimal compared to the debugging overhead of finding corruption deep in a pipeline. A few milliseconds of JSON validation per handoff saves hours of debugging later. That's a trade any team should take.

This is the difference between systems you trust and systems that keep you up at night.

Scaling Beyond Your First Agent Chain

The patterns we've discussed work beautifully when you have five agents. But what happens when your system grows to fifty agents? When you're running parallel agent chains? When agents need to share data structures that are too large to fit in prompts?

That's when architectural thinking becomes critical.

Consider a scenario where you're running multiple agent pipelines simultaneously. Agent A (researcher) and Agent B (competitor-analyst) are both running in parallel, gathering different data. Once both complete, Agent C (synthesizer) needs to combine their outputs into a unified strategic analysis. Without proper handoff structures, Agent C doesn't know when both inputs are ready, how to find them, or how to parse them.

You'd need to implement a coordination layer—something that tracks which agents have finished, where their outputs live, and triggers downstream agents only when all prerequisites are satisfied. This is why professional agent systems use job queues, state machines, or workflow orchestration platforms.

The file-based communication pattern scales to handle this. Each agent writes to a uniquely-named file. A coordinator checks for the existence of required files before proceeding. If a file is missing, the coordinator waits or retries. If it's corrupted, it raises an error. This approach is infinitely more robust than trying to pass complex data structures through prompts.

Real-World Failure Modes and Recovery

Theory is great until production hits. Let me walk you through actual failure modes we encounter:

Partial Completion: An agent times out halfway through its work. It returns an incomplete result file. The orchestrator doesn't check for completion markers and passes a half-baked result to the next agent. The next agent chokes trying to parse incomplete JSON.

Network Flakiness: An agent successfully completes but its file write fails due to a network hiccup. The orchestrator thinks everything succeeded, but the file doesn't exist.

Token Limit Hits: An agent runs out of tokens partway through generating output. It returns a truncated file that looks complete but is missing critical data.

Silent Failures: An agent encounters an internal error but doesn't propagate it properly. The result file contains an error message instead of structured data, but the orchestrator treats it as success.

File Permission Issues: On some systems, a file written by one agent is unreadable by the next agent due to permission restrictions.

Real systems need to handle all of these. That's why the result format includes metadata: status indicators, completion percentages, timestamps, checksums. You can validate that a result is actually complete before consuming it.

plaintext
[Example from real failure recovery]
✓ AGENT-A: Completed research
Location: /workspace/research-2026-03-16-14-23.json
Timestamp: 2026-03-16T14:23:41Z
Completeness: 100%
Checksum: sha256:a7f9e8d...
 
[Next agent checks]
- Status: ✓ (success)
- File exists: yes
- Completeness: 100% (not 87%)
- Timestamp: valid (within last 5 minutes)
- Checksum: verifies
[All checks pass, proceed safely]

This is the difference between hope-based systems and robust systems.

Memory and Context Windows in Long Pipelines

Here's something that catches many people: as pipelines grow longer, your orchestrator's context window fills up with metadata about all the previous stages, even though you're using file-based communication.

A 20-stage pipeline means your orchestrator is writing 20 prompts to the next stage, parsing 20 results, extracting 20 file paths. That metadata accumulates. Not in a way that breaks anything, but it squeezes the space you have for actual reasoning.

Smart orchestrators implement memory cleaning. After each stage, they discard the full result text (keeping only the file path) and remove completed stages from the prompt. The orchestrator remembers "I've already run stages 1-15, they're done" but doesn't repeat their full outputs.

Some systems implement checkpoint garbage collection: after confirming a stage has been successfully consumed downstream, they delete the checkpoint file to save disk space. Others compress old output files or archive them to slower storage.

These are details that matter when your system runs hundreds of times a day or manages petabytes of accumulated intermediate data.

Building Organizational Alignment Around Agent Communication

The technical patterns are only half the battle. The other half is getting your team to actually follow them.

If every developer writes agents with different output formats, you'll end up with a Tower of Babel where nobody can integrate anything. This is why organizations building serious agent systems create standards documents. They define:

  • Required result format (every agent must return status, file location, timestamp, metadata)
  • File naming conventions (who names files, what information goes in the name)
  • Error handling contracts (how agents signal failure, what escalation looks like)
  • Testing requirements (agents must pass integration tests before deployment)

When Agent A and Agent B are written by different teams, they can still interoperate because they follow the same communication contract. A new developer joining can write an agent knowing exactly what format to produce and what format to expect from dependencies.

This is what maturity looks like in agent systems: not individual brilliance, but institutional discipline about how components talk to each other.

Debugging Agent Communication Failures

When things go wrong, structured communication patterns make debugging exponentially easier. Instead of staring at cryptic error messages buried in wall-of-text outputs, you can systematically trace where communication failed. Start by checking the result file at each stage. Is it present? Is it valid JSON or properly formatted? Does it contain the expected status indicator? These checks happen in seconds and pinpoint the exact agent that failed. The timestamp metadata tells you when the failure occurred, helping you correlate with any system events or resource constraints happening around that time. Agents that return invalid data become immediately visible. You can then decide whether to retry the agent, manually inspect the upstream results it was supposed to consume, or escalate to human review. The transparency is invaluable.

The Debugging Workflow in Practice

Here's what systematic debugging actually looks like when you've built communication discipline. Let's say a five-agent pipeline fails at stage 3. Instead of re-running everything or guessing, you follow this process:

First, you check the result files from each stage. Stage 1 completed successfully—its result file exists, has a valid completion timestamp, and validates against the schema. Stage 2 also succeeded. But stage 3 has no result file at all, or it has one with a ✗ FAILED status indicator. You've immediately narrowed the problem to a single agent.

Next, you read stage 3's result file. If it exists but failed, it tells you why: maybe a timeout, maybe a parsing error on the input it received from stage 2, maybe a rate limit. If the file doesn't exist, you check the logs for stage 3. Did it even run? Did it crash before producing output? This diagnostic flow is possible because you designed structured communication.

Compare this to systems that dump free-form text: you'd be reading through thousands of words of output from each agent, trying to figure out which one actually had the problem. With structured formats, you drill down in minutes.

Then you have a choice: fix the root cause and retry from stage 3, or fix it and replay from an earlier checkpoint. If the problem was data corruption from stage 2, you might need to re-run stage 2. If it was a transient timeout in stage 3, you just retry stage 3. The decision is informed by what the structured output told you.

Monitoring and Observability Through Communication Patterns

Structured result formats also enable rich observability. You can emit metrics at every stage:

  • How long did each agent take?
  • What was the result file size? (Indicates complexity of downstream processing)
  • Did it fail and how many retries did it need?
  • What resources did it consume? (Token count, time, file I/O)

These metrics feed into dashboards. You can see at a glance that stage 2 is always slow, or stage 4 fails 5% of the time, or stage 3's output files are growing exponentially. These signals guide optimization: maybe stage 2 needs a faster model, or stage 4 needs better error handling, or stage 3 is processing too much data.

Without structured communication, most of this visibility is invisible. You know "the pipeline failed" but not where or why. With structured formats, you have forensic visibility into exactly what happened.

Evolving Communication Patterns as Systems Grow

One critical thing: your communication patterns will evolve. The structure that works for a 3-agent pipeline might not scale to 30 agents. Here's what typically changes as systems grow:

Small systems (1-5 agents) can get away with loose structure. File paths and basic status indicators suffice.

Growing systems (5-15 agents) need formal schemas. You introduce versioning (result format v1.0, v2.0) so agents from different eras can coexist.

Large systems (15+ agents) add typed communication protocols. Instead of loose strings, you're passing structured data with type validation. Instead of file paths, you might use distributed caches or message queues. Instead of filesystem I/O, you use databases or cloud storage.

The evolution path looks like: filesystem → typed schemas → message queues → distributed coordination systems. Each level adds complexity but enables new capabilities. A small startup might stop at "filesystem with structured formats." A company running hundreds of agents daily might need message queues and distributed tracing.

The key: recognize which level you're at and use patterns appropriate to that scale. Don't over-engineer early; don't under-architect as you scale.

Summary

Agent communication in Claude Code follows a few hard-won principles:

  1. Agents return text, not objects. Parse that text reliably with structured formats.

  2. Large data lives in files. Pass file paths in prompts, not full content.

  3. Use standard result schemas. Make it easy to parse success/failure, metadata, and artifact locations.

  4. Sequential pipelines chain file paths. Agent A writes → Orchestrator reads → passes path to Agent B.

  5. Check results explicitly. Don't assume success; validate status and error details.

  6. Checkpoint strategically. Let pipelines resume from failures without re-running everything.

  7. Use the right format for the job: JSON for complex data, YAML for outlines/configs, CSV for tabular facts.

When you follow these patterns, you can build pipelines that are:

  • Efficient: No redundant data passing or token waste
  • Debuggable: Clear file artifacts at each stage
  • Resilient: Errors stop gracefully; pipelines can resume
  • Scalable: Works with hundreds of agents in long chains

The key insight: Don't think of agent results as text to paste into the next prompt. Think of them as structured outputs that write to disk and return references.

That's how professional Claude Code systems coordinate work. You're not copying data; you're referencing it. You're not drowning in context; you're managing a distributed file system where each agent reads only what it needs.

Build systems this way, and you'll find that orchestrating 5 agents feels as easy as orchestrating 50. The pattern scales because you've decoupled agent outputs from the orchestrator's context window.

—-iNet

Need help implementing this?

We build automation systems like this for clients every day.

Discuss Your Project