Agent Patterns Hub

The Complete Guide to AI Agent Orchestration Patterns

Most AI agents fail in production. Not because the underlying model is bad, but because the orchestration is brittle. The agent works on happy paths during testing, then breaks on the first edge case in production.

After building an autonomous agent system that has executed 617 operations autonomously across 840+ commits, here are the orchestration patterns that actually survive contact with reality.

Pattern 1: Task Decomposition with Dependency Graphs

Never send a complex task as a single prompt. The model loses track of requirements, skips steps, and hallucinates completion.

Instead, decompose the task into a directed acyclic graph (DAG) of subtasks. Each subtask has explicit dependencies and a verification criterion.

// Decompose: "Build an API that analyzes code quality"
const subtasks = [
  { id: 'T1', title: 'Define API contract', depends_on: [], verify: 'Schema written' },
  { id: 'T2', title: 'Implement parser', depends_on: ['T1'], verify: 'Tests pass' },
  { id: 'T3', title: 'Implement analyzer', depends_on: ['T1'], verify: 'Tests pass' },
  { id: 'T4', title: 'Integrate and test', depends_on: ['T2', 'T3'], verify: 'E2E pass' },
  { id: 'T5', title: 'Deploy', depends_on: ['T4'], verify: 'Health check 200' },
];

// T2 and T3 can run in parallel (same wave)
// Critical path: T1 -> T3 -> T4 -> T5

The key insight: verification criteria are not optional. Without them, the agent will report "done" on incomplete work. Each subtask must have a concrete, checkable condition.

Pattern 2: Quality Gates

Before any agent output moves to the next step, it passes through a quality gate. This is a multi-dimensional check that returns pass/fail with specific findings.

function qualityGate(output: string, dimensions: string[]): QualityResult {
  const scores = dimensions.map(dim => assess(output, dim));
  const pass = scores.every(s => s.score >= threshold);

  return {
    pass,
    scores,
    findings: scores.filter(s => s.score < threshold).flatMap(s => s.findings),
  };
}

// Dimensions for code: correctness, clarity, completeness, robustness, efficiency
// Dimensions for text: clarity, completeness, conciseness

In practice, quality gates catch 60-70% of agent errors before they propagate. The cost of running a quality check ($0.01) is negligible compared to the cost of debugging a failure cascading through 10 downstream steps.

Pattern 3: Cost-Optimal Hierarchical Dispatch (COHD)

Not all steps require the same intelligence level. COHD routes each subtask to the cheapest model capable of handling it.

// Classification: simple (extraction, formatting) -> cheap model
// Classification: moderate (analysis, comparison) -> mid model
// Classification: complex (reasoning, planning) -> expensive model

function dispatch(step: AgentStep): Model {
  if (step.complexity < 0.3) return 'haiku';     // $0.25/MTok
  if (step.complexity < 0.7) return 'sonnet';     // $3/MTok
  return 'opus';                                   // $15/MTok
}

// 80% of steps route to cheap model = 88% cost reduction

Pattern 4: Context-Preserving Recursive Delegation (CPRD)

When you delegate work to a sub-agent, critical context is often lost. The sub-agent does not know the broader goal, the constraints, or the decisions already made.

CPRD solves this by maintaining a context summary that propagates through the delegation chain:

interface DelegationContext {
  goal: string;           // The top-level objective
  constraints: string[];  // Hard constraints that must not be violated
  decisions: string[];    // Decisions already made by parent agents
  depth: number;          // Current delegation depth (for recursion limits)
}

async function delegate(task: string, context: DelegationContext): Promise<Result> {
  if (context.depth > MAX_DEPTH) {
    throw new Error('Delegation depth exceeded');
  }

  return await subAgent.execute({
    task,
    systemContext: `
      Top-level goal: ${context.goal}
      Constraints: ${context.constraints.join('; ')}
      Decisions already made: ${context.decisions.join('; ')}
      Your role: Complete this specific subtask within the above constraints.
    `,
  });
}

Pattern 5: Circuit Breakers for Agent Operations

Agents can get stuck in loops, spend unbounded money on API calls, or produce cascading failures. Circuit breakers prevent catastrophic outcomes.

class AgentCircuitBreaker {
  private failures = 0;
  private state: 'closed' | 'open' | 'half-open' = 'closed';

  async execute(operation: () => Promise<any>): Promise<any> {
    if (this.state === 'open') {
      throw new CircuitOpenError('Agent operation halted -- too many failures');
    }

    try {
      const result = await operation();
      this.failures = 0;
      this.state = 'closed';
      return result;
    } catch (error) {
      this.failures++;
      if (this.failures >= THRESHOLD) {
        this.state = 'open';
        alert('Circuit breaker tripped: agent operations halted');
        setTimeout(() => { this.state = 'half-open'; }, COOLDOWN_MS);
      }
      throw error;
    }
  }
}

// Additional breakers:
// - Budget breaker: halt if cost exceeds 80% of budget
// - Time breaker: halt if step exceeds expected duration by 3x
// - Error rate breaker: halt if >10% of requests fail

Pattern 6: Failure Analysis and Auto-Recovery

When a step fails, the default agent behavior is either to retry blindly or to give up. Both are wrong. The correct approach is to diagnose the failure and adapt.

async function executeWithRecovery(step: AgentStep, maxRetries = 3): Promise<Result> {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    try {
      const result = await execute(step);
      const quality = qualityGate(result);
      if (quality.pass) return result;

      // Quality gate failed -- diagnose and adapt
      step = adaptStep(step, quality.findings);
    } catch (error) {
      const diagnosis = failureAnalysis(error, step);

      if (diagnosis.category === 'transient') {
        await sleep(exponentialBackoff(attempt));
        continue;
      }

      if (diagnosis.category === 'input_error') {
        step = reformulateStep(step, diagnosis);
        continue;
      }

      // Permanent failure -- escalate
      throw new PermanentFailure(diagnosis);
    }
  }

  throw new MaxRetriesExceeded(step);
}

Pattern 7: Measurement Substrate

You cannot improve what you do not measure. Every agent operation should automatically track:

  • Cost: Token usage per step, total cost per workflow run
  • Latency: Time per step, total workflow time, time waiting vs processing
  • Quality: Quality gate pass/fail rates, error rates per step
  • Revenue: If the agent is generating revenue, track it at the source (Stripe webhook, wallet balance)

This data feeds back into optimization. The steps that are most expensive get optimized first. The steps that fail most often get reinforced with better quality gates. Revenue data determines whether the entire system is viable.

Get the Full Playbook

All 15 patterns with implementation templates in TypeScript and Python.

Protocol Playbook - $29

Infrastructure That Makes This Work

The patterns above are implementation-agnostic, but here is the stack that works well in practice:

  • Cloudflare Workers for serverless deployment -- near-zero cost at low traffic, auto-scales, built-in AI Gateway for model routing and caching
  • Neon Postgres for state management -- serverless database with auto-scaling, no administration overhead
  • Stripe for billing -- handles the full subscription lifecycle including retries and dunning
  • x402 protocol for agent-to-agent payments -- HTTP-native stablecoin micropayments with sub-second settlement

The key architectural principle: every component should be serverless. Fixed infrastructure costs create a baseline expense that kills autonomous systems before they generate revenue. With serverless, you pay proportional to usage -- which means an organism with zero traffic costs zero dollars.