5 Agent Skill Design Patterns: From Google's ADK to Claude Code

Beginner52m readFull-stack developers

Google published 5 agent skill design patterns every ADK developer should know. This guide maps each pattern to a production-tested Claude Code skill implementation — with examples from an 80+ skill library.

Primary Focus

ai development

AI Tools Covered

AI-firstNext.jsConvex

What You'll Learn

  • The Problem with Ad-Hoc Agent Instructions
  • Google's ADK and the Pattern Taxonomy
  • SKILL.md -- Claude Code's Skill Format
  • When Order Matters
  • The Content Publishing Pipeline
  • Pipeline Anti-Patterns

Guide Curriculum

Why Agent Skills Need Design Patterns

Learn key concepts

3 lessons
  • The Problem with Ad-Hoc Agent Instructions10m
  • Google's ADK and the Pattern Taxonomy10m
  • SKILL.md -- Claude Code's Skill Format10m

Pattern 1 -- Sequential Pipeline

Learn key concepts

3 lessons
  • When Order Matters10m
  • The Content Publishing Pipeline10m
  • Pipeline Anti-Patterns10m

Pattern 2 -- Branching Router

Learn key concepts

3 lessons
  • Dynamic Path Selection10m
  • The Content Command Router10m
  • Router Design Principles10m

Pattern 3 -- Fan-Out Aggregator

Learn key concepts

3 lessons
  • Parallel Execution and Result Merging10m
  • The Multi-Agent Review Skill10m
  • Aggregation Strategies10m

Pattern 4 -- Stateful Loop

Learn key concepts

3 lessons
  • Iterate Until Done10m
  • The Self-Healing Test Skill10m
  • Loop Safety and Exit Conditions10m

Pattern 5 -- Delegation Chain

Learn key concepts

3 lessons
  • Hierarchical Task Decomposition10m
  • The Full-Stack Feature Skill10m
  • Delegation Boundaries and Context Management10m

Composing Patterns and Building Your Skill Library

Learn key concepts

3 lessons
  • Pattern Composition Rules10m
  • Building a Skill Library That Scales10m
  • From Google ADK to Your Own Framework10m

Reference -- Pattern Selection Cheat Sheet

Learn key concepts

2 lessons
  • Decision Matrix10m
  • Quick Reference Card10m

Preview: First Lesson

Why Agent Skills Need Design Patterns

The Problem with Ad-Hoc Agent Instructions

The Problem with Ad-Hoc Agent Instructions

In the world of agentic tools, developers often encounter a familiar challenge: inconsistency. Initially, your first few prompts yield satisfactory results. However, as you progress to your 50th prompt, you find yourself repeating instructions. By the time you reach your 100th prompt, you’re dealing with scattered, contradictory instructions, leading to unpredictable agent behavior.

This chaos mirrors a problem that software engineering addressed long ago with design patterns. The Gang of Four didn’t document patterns like Singleton or Observer out of boredom; they identified and formalized solutions to recurring problems. Agent skills demand a similar structured approach.

The Pitfalls of Lacking Patterns

Imagine a scenario involving a team of three developers working on the same project with Claude Code. Developer A creates a deployment prompt that prioritizes running tests. Developer B opts for a prompt that skips tests but checks TypeScript errors. Meanwhile, Developer C borrows a prompt from a blog post. Within a week, the project suffers from three distinct deployment behaviors, none of which are documented or consistent.

# Developer A's ad-hoc prompt (buried in chat history)
"Deploy to production. Run tests first. If they pass, push to main."

# Developer B's ad-hoc prompt (in a sticky note)
"Check for TS errors, then build and deploy. Skip tests, they're flaky."

# Developer C's ad-hoc prompt (from a blo
Free Access

Start learning with this comprehensive guide

This guide includes:

8 modules with 23 lessons
52m estimated reading time

About the Author

H
✨ Vibe Coder
@hiram-clark

Hiram Clark is the founder of vybecoding.ai and editor of every guide and news article published on the site. He reviews all AI-drafted content for accuracy before publication and is personally accountable for factual errors. He works hands-on with the AI development tools, workflows, and infrastructure covered here.

Full Guide Content

Complete lesson text — start the interactive course above for exercises and progress tracking.

Module 1Why Agent Skills Need Design Patterns

1.1The Problem with Ad-Hoc Agent Instructions

The Problem with Ad-Hoc Agent Instructions

In the world of agentic tools, developers often encounter a familiar challenge: inconsistency. Initially, your first few prompts yield satisfactory results. However, as you progress to your 50th prompt, you find yourself repeating instructions. By the time you reach your 100th prompt, you’re dealing with scattered, contradictory instructions, leading to unpredictable agent behavior.

This chaos mirrors a problem that software engineering addressed long ago with design patterns. The Gang of Four didn’t document patterns like Singleton or Observer out of boredom; they identified and formalized solutions to recurring problems. Agent skills demand a similar structured approach.

The Pitfalls of Lacking Patterns

Imagine a scenario involving a team of three developers working on the same project with Claude Code. Developer A creates a deployment prompt that prioritizes running tests. Developer B opts for a prompt that skips tests but checks TypeScript errors. Meanwhile, Developer C borrows a prompt from a blog post. Within a week, the project suffers from three distinct deployment behaviors, none of which are documented or consistent.

# Developer A's ad-hoc prompt (buried in chat history)
"Deploy to production. Run tests first. If they pass, push to main."

# Developer B's ad-hoc prompt (in a sticky note)
"Check for TS errors, then build and deploy. Skip tests, they're flaky."

# Developer C's ad-hoc prompt (from a blog post)
"Do a production deployment following best practices."

The outcome? Inconsistent deployments, occasional broken builds, and a lack of traceability. The agent’s behavior becomes unpredictable, hinging on the last prompt it received.

Understanding Agent Skills

An agent skill is a reusable, self-contained instruction set that guides an AI agent in executing a specific task. It comprises:

  • Context: Information the agent needs before starting
  • Steps: The sequence of actions to perform
  • Constraints: Boundaries within which the agent must operate
  • Output: The criteria for success

In Claude Code, skills are encapsulated in SKILL.md files located in the .claude/skills/ directory. When a skill is invoked—either through a slash command or direct reference—the agent loads this file as context and adheres to its instructions.

Google's ADK employs a similar concept, referring to them as "tools" and "sub-agents." Despite the different terminology, the underlying patterns are the same. This formalization is crucial as it transforms agent behavior from arbitrary actions into a documented, testable, and repeatable process.

The Transformation with Skills

Before Skills

Without skills, a command like "Hey Claude, deploy my app" leaves the agent to interpret your deployment process. This can result in varied outcomes—sometimes tests are run, sometimes they aren’t, and occasionally, deployments occur in the wrong environment.

After Skills

With skills, a command such as "Run the deploy skill" triggers a specific SKILL.md file. This file outlines every step, constraint, and expected output. The agent consistently follows the same process, ensuring reliability and predictability, regardless of who initiates the command.

Conclusion

Adopting design patterns for agent skills is not just a best practice; it's a necessity for maintaining consistency and reliability in AI-driven processes. By formalizing instructions into skills, developers can ensure that their agents perform tasks predictably and efficiently, transforming chaotic ad-hoc instructions into a streamlined, repeatable workflow. Embrace the rigor of design patterns for your agent skills and watch your projects thrive with clarity and precision.

1.2Google's ADK and the Pattern Taxonomy

Google's ADK and the Pattern Taxonomy

In early 2026, Google's Agent Development Kit (ADK) documentation brought clarity to a concept that many developers had already grasped intuitively: agent skills consistently fall into five distinct patterns. These patterns are not arbitrary; they arise from the fundamental ways in which agents interact with systems, data, and other agents.

The Five Core Patterns

Understanding these patterns is crucial for designing efficient and reliable agent skills. Let's delve into each pattern:

  1. Sequential Pipeline

This pattern involves executing steps in a predetermined order. It is ideal for tasks that require a linear flow, ensuring each step is completed before the next begins.

  1. Branching Router

Here, skills determine different paths based on input conditions. This pattern is perfect for scenarios where decisions need to be made dynamically, directing the flow accordingly.

  1. Fan-Out Aggregator

This pattern allows for parallelizing tasks and then merging the results. It is particularly useful for operations that can be executed concurrently, improving efficiency and speed.

  1. Stateful Loop

Skills utilizing this pattern iterate until a specific condition is met. This is essential for tasks that require repeated execution until a desired state is achieved.

  1. Delegation Chain

This involves handing off tasks to sub-agents or sub-skills. It is beneficial for complex operations that can be broken down into smaller, manageable components.

Each pattern addresses a unique class of problems. Selecting the wrong pattern can lead to inefficiencies, such as infinite loops, skipped steps, or erroneous outputs.

Why These Five Patterns?

These patterns correspond to fundamental computational concepts. The Sequential Pipeline mirrors linear execution, Branching Router aligns with conditional branching, Fan-Out Aggregator reflects parallel execution, Stateful Loop embodies iteration, and Delegation Chain represents function composition. These are the building blocks of programming, now applied to agent orchestration.

Google did not invent these patterns; they emerged naturally across various ADK projects and were subsequently formalized. Similar patterns can be observed in LangChain's chains, CrewAI's processes, AutoGen's conversation patterns, and Claude Code's SKILL.md files. This convergence is not coincidental—it reflects the limited number of effective ways to structure work.

Consequences of Using the Wrong Pattern

Choosing the incorrect pattern can lead to significant issues, not just inefficiencies. It can result in unreliable agents that produce seemingly correct results until they fail in production. Here are some examples:

| Situation | Wrong Pattern | What Goes Wrong | Right Pattern |

|-------------------------------|---------------------|-----------------------------------------------------------|----------------------|

| Deploy to production | Fan-Out | Tests and deployment occur simultaneously, risking errors | Sequential Pipeline |

| Handle different content types| Sequential Pipeline | Agent applies guide logic to news articles | Branching Router |

| Run 3 independent code checks | Sequential Pipeline | Takes three times longer than necessary | Fan-Out Aggregator |

| Fix failing tests | Sequential Pipeline | Agent stops after one fix, even if tests still fail | Stateful Loop |

| Build full-stack feature | Single Pipeline | A single failure halts a 20-step process | Delegation Chain |

The impact of selecting the wrong pattern extends beyond inefficiency. It compromises reliability, leading to subtle errors that may go unnoticed until they cause significant issues in production.

Conclusion

Understanding and applying the correct design patterns for agent skills is crucial for developing robust and efficient systems. These five patterns—Sequential Pipeline, Branching Router, Fan-Out Aggregator, Stateful Loop, and Delegation Chain—provide a framework for addressing a wide range of problems. By aligning your agent skills with these patterns, you can enhance reliability and performance, ensuring your agents operate smoothly and effectively in production environments.

1.3SKILL.md -- Claude Code's Skill Format

SKILL.md -- Claude Code's Skill Format

In this lesson, you'll explore the anatomy of a Claude Code skill file, a structured format that ensures your agent skills are robust and reliable. By understanding this format, you'll be able to design skills that are both effective and safe to execute in production environments.

Anatomy of a Claude Code Skill File

Before diving into design patterns, let's dissect the structure of a Claude Code skill file. Here's an example of a skill designed to deploy an application to production:

Base directory for this skill: /home/user/project/.claude/skills/deploy

# Deploy to Production

**Purpose**: Deploy the application to production with safety checks

## Prerequisites
- All tests passing
- No uncommitted changes
- On the main branch

## Steps
1. Run the test suite
2. Check for TypeScript errors
3. Build the production bundle
4. Deploy via Vercel CLI
5. Verify deployment health

## Constraints
- NEVER deploy with failing tests
- ALWAYS verify the health endpoint after deploy
- If any step fails, stop and report the error

## Output
- Deployment URL
- Health check status
- Build time and bundle size

Key Elements of a Skill File

  • Base Directory: This is the foundational path where the skill operates. It's crucial because it ensures the agent executes commands in the correct directory, preventing errors or unintended modifications to other projects.
  • Purpose: A concise, one-line description that is critical for pattern selection. This line helps determine if this skill should be delegated to when other skills need assistance.
  • Prerequisites, Steps, Constraints, Output: These are the four pillars of any skill, each serving a distinct role in the skill's execution.

A Deeper Look at Each Pillar

Prerequisites

Prerequisites are the preconditions that must be verified before the skill can execute. Think of them as guard clauses that prevent errors. Without prerequisites, a skill might deploy uncommitted changes or run tests against outdated builds.

## Prerequisites
- All tests passing (run `npm run test` to verify)
- No uncommitted changes (check with `git status`)
- On the main branch (check with `git branch --show-current`)
- .env.local exists with CONVEX_DEPLOYMENT set

Including explicit checks, such as using git status, removes ambiguity and ensures the agent knows exactly what to verify.

Steps

Steps outline the execution sequence. Each step should be a discrete action with a clear completion state. Avoid vague instructions like "set up the project." Instead, specify actions like "run npm install and verify zero audit vulnerabilities."

Constraints

Constraints act as guardrails, preventing the agent from causing damage. They are the most critical section, ensuring that the agent doesn't take harmful shortcuts, like deleting failing tests to pass them.

## Constraints
- NEVER deploy with failing tests
- NEVER modify test files to make them pass (fix the source code instead)
- ALWAYS verify the health endpoint responds 200 after deploy
- If any step fails, stop immediately and report the error
- Do not proceed past step 3 if bundle size exceeds 5MB

Output

Output defines what a successful execution looks like, providing clarity for both the agent and any human reviewers. Without defined outputs, the agent might complete all steps but leave you to manually verify everything.

Comparison with Google ADK

This format aligns closely with Google's ADK tool definitions, differing primarily in syntax. While ADK uses Python decorators and JSON schemas, Claude Code employs markdown. Here's a conceptual comparison:

# Google ADK equivalent (conceptual)
@tool(
    name="deploy_to_production",
    description="Deploy the application to production with safety checks",
    prerequisites=["tests_passing", "clean_git", "main_branch"],
)
def deploy_to_production(project_path: str) -> DeployResult:
    run_tests(project_path)
    check_typescript(project_path)
    build_production(project_path)
    deploy_vercel(project_path)
    return verify_health(project_path)

Both formats share the same structure and intent, emphasizing the importance of the underlying pattern.

Conclusion

Understanding the anatomy of a Claude Code skill file is essential for designing effective and safe agent skills. By adhering to the structured format of base directory, purpose, prerequisites, steps, constraints, and output, you ensure that your skills are reliable and easy to manage. This knowledge empowers you to create robust skills that integrate seamlessly with other tools and frameworks, enhancing your development workflow.

Module 2Pattern 1 -- Sequential Pipeline

2.1When Order Matters

When Order Matters

In the world of software development, understanding when and how to use a Sequential Pipeline can significantly enhance your workflow efficiency. This lesson dives into the Sequential Pipeline pattern, a fundamental concept where tasks are executed in a specific order, ensuring that each step's output seamlessly becomes the input for the next. We'll explore when this pattern is most effective, when to avoid it, and how to conceptualize it in real-world scenarios.

Understanding the Sequential Pipeline

The Sequential Pipeline is a straightforward yet powerful design pattern. It ensures that processes occur in a predetermined sequence, where each step builds upon the previous one. This pattern is crucial when tasks have a natural order or when subsequent steps rely on the outputs of earlier ones. If any step fails, the pipeline halts, preventing the propagation of errors.

When to Use a Sequential Pipeline

Consider employing a Sequential Pipeline in scenarios such as:

  • Natural Order of Tasks: When tasks must occur in a specific sequence, such as building an application before deploying it or validating data before saving it.
  • Dependency on Previous Outputs: When each step relies on the successful completion and output of the preceding step.
  • Guaranteed Execution Order: When the order of execution is critical to the task's success.
  • Step-by-Step Rollback: When a failure requires a systematic rollback of completed steps.

When to Avoid a Sequential Pipeline

Avoid using a Sequential Pipeline when:

  • Independent Steps: If the steps can be executed independently of each other, consider using a Fan-Out pattern instead.
  • Diverse Input Processing: When different inputs require distinct processing paths, a Router pattern may be more appropriate.

The Mental Model: Assembly Line Analogy

Visualize a Sequential Pipeline as an assembly line in a factory. Each station on the line adds a specific component to the product. Skipping a station results in an incomplete or defective product, while executing stations out of order leads to chaos. For example, you wouldn't attach doors to a car without first constructing the frame.

Real-World Analogy Map

Here's how a Sequential Pipeline maps to an assembly line:

| Assembly Line Task | Sequential Pipeline Step |

|---------------------------|----------------------------------|

| Raw materials arrive | Input file or user request received |

| Station 1: Cut metal | Step 1: Validate input |

| Station 2: Weld frame | Step 2: Transform data |

| Station 3: Paint | Step 3: Generate output |

| Station 4: Quality check | Step 4: Verify result |

| Finished product | Deliverable (e.g., deployed app, published content) |

Key Difference

Unlike physical assembly lines, software pipelines lack inherent constraints that enforce order. In software, explicit step numbering and dependencies are essential to prevent skipping steps or executing them out of sequence. Without these controls, the process could easily derail, much like a car assembly line attempting to install doors before the frame is ready.

Conclusion

The Sequential Pipeline is an indispensable pattern for tasks that require a strict order of execution. By ensuring each step is completed before the next begins, you maintain the integrity and reliability of your processes. However, it's crucial to recognize when this pattern is appropriate and when alternative patterns might better suit your needs. By mastering the Sequential Pipeline, you can streamline your workflows and enhance the quality of your outputs, much like a well-oiled assembly line producing flawless products.

2.2The Content Publishing Pipeline

The Content Publishing Pipeline

Welcome to the "Content Publishing Pipeline" lesson, where you'll learn how to transform a markdown file into a polished, production-ready guide. This lesson is part of the "Pattern 1 -- Sequential Pipeline" module, which emphasizes the importance of a methodical, step-by-step approach to content deployment. By the end of this lesson, you'll understand how to validate, parse, and publish content efficiently, ensuring high-quality output with minimal errors.

Prerequisites

Before diving into the pipeline, ensure you have the following:

  • A markdown file located at the specified path.
  • The file must include valid YAML frontmatter with fields for the title, description, category, and tags.
  • Confirmation that the content is intended for production deployment, not development.

Steps in the Content Publishing Pipeline

1. Validate Source File

The first step is to ensure the integrity and readiness of your source file:

  • Existence Check: Verify that the markdown file exists at the given path.
  • Frontmatter Parsing: Extract and confirm the presence of required fields (title, description, category, tags).
  • Validation Report: If any field is missing, reject the file. Otherwise, report: "Validated: [title] with [N] modules detected."

2. Parse Structure

Next, delve into the content's structure:

  • Module and Lesson Extraction: Identify modules (## headings) and lessons (### headings).
  • Structural Validation: Ensure a minimum of 2 modules and 2 lessons per module.
  • Lesson Type Detection: Classify lessons into types such as text, code, exercise, and quiz.
  • Parsing Report: Summarize with: "Parsed: [N] modules, [M] lessons, types: [list]."

3. Generate Metadata

With the structure parsed, generate essential metadata:

  • Learning Outcomes: Derive 3-6 learning outcomes from the content.
  • Difficulty and Time Estimation: Infer difficulty level if unspecified and estimate completion time.
  • Metadata Report: Provide details: "Metadata: [difficulty], [time], [N] outcomes."

4. Deploy to Database

Now, it's time to deploy your guide:

  • Mutation Execution: Use the createPrivilegedStructuredGuide mutation to target the production database (modest-lobster-37).
  • Verification: Confirm creation by querying the returned ID.
  • Deployment Report: Announce: "Deployed: ID [id] to production."

5. Verify Publication

Finally, ensure everything is live and accurate:

  • Guide Retrieval: Fetch the guide by slug from production.
  • Rendering Confirmation: Check that all modules and lessons are correctly rendered.
  • Live Report: Confirm with: "Live at: [url] with [N] modules verified."

Why This Works as a Pipeline

The sequential nature of this pipeline is crucial. Each step is dependent on the output of the previous one, ensuring a smooth flow from validation to verification. Attempting to parallelize steps, such as validating and generating metadata simultaneously, would disrupt this flow, as metadata generation relies on parsed content. Skipping verification might seem feasible, but it would leave potential rendering issues unchecked. This dependency chain is what defines a pipeline, ensuring reliability and consistency.

The Impact of a Structured Approach

Before the Pipeline

In the past, content publication was ad-hoc and error-prone:

"Hey Claude, publish this guide to production"

This casual approach often led to skipped validations, incorrect parsing, and overlooked verifications, resulting in about 30% of publications requiring manual corrections.

After Implementing the Pipeline

With the structured pipeline in place, every publication adheres to the same rigorous steps. Failures are identified at the specific step where they occur, providing clear error messages. This clarity allows for quick fixes to the input, reducing the need for debugging the agent's behavior. The result? A dramatic reduction in publication errors, now under 2%.

Conclusion

The Content Publishing Pipeline exemplifies the power of a structured, sequential approach to content deployment. By following these five steps, you ensure that each piece of content is thoroughly validated, accurately parsed, and reliably published. This method not only enhances the quality of your output but also streamlines the process, minimizing errors and maximizing efficiency. Embrace this pipeline to elevate your content publishing skills and deliver consistently excellent results.

2.3Pipeline Anti-Patterns

Pipeline Anti-Patterns

In the world of software development, pipelines are essential for automating workflows and ensuring consistent, reliable processes. However, even the best-intentioned pipelines can fall victim to anti-patterns that hinder their effectiveness. In this lesson, we'll explore common pitfalls in sequential pipelines and provide actionable strategies to avoid them. By the end, you'll be equipped to design pipelines that are robust, efficient, and easy to maintain.

Understanding Sequential Pipeline Anti-Patterns

Sequential pipelines are a straightforward approach to task automation, where each step depends on the successful completion of the previous one. While this linear structure is intuitive, it can also lead to several anti-patterns that compromise the pipeline's efficiency and reliability.

Guideline 1: Limit Pipeline Length

One of the most prevalent issues with sequential pipelines is excessive length. Long pipelines are fragile; a failure in one step can cascade through the entire process, making it difficult to trace the root cause of errors.

Recommendation: Keep pipelines under seven steps. If your process requires more, consider breaking it into sub-skills. This guideline isn't arbitrary; it's based on the observation that long sequences can cause large language models (LLMs) to lose context, leading to confusion. For instance, in a 12-step pipeline, an agent might mistakenly associate the output of step 8 with step 6.

Guideline 2: Ensure Idempotency

Idempotency is a critical property for each step in your pipeline. An idempotent step can be executed multiple times without changing the result beyond the initial application. This property is crucial for safely restarting a pipeline after a failure.

Recommendation: Make each step idempotent when possible. For example, if step 3 involves creating a database record, re-running it should either skip the creation if the record already exists or clean up and recreate it. Without idempotency, restarting a failed pipeline can lead to data corruption or inconsistent states.

Guideline 3: Implement Explicit Failure Handling

Pipelines should be designed with failure in mind. Relying on agents to intuitively handle errors can lead to incomplete or incorrect recovery actions.

Recommendation: Include explicit failure handling in your pipeline design. Instead of hoping the agent will manage failures, define clear actions for each step. For example, "If step 3 fails, do X" provides a concrete recovery path.

Anti-Pattern: The Mega Pipeline

A common anti-pattern is the "Mega Pipeline," where a monolithic sequence of steps is used to handle complex processes. This approach often mixes different patterns, leading to confusion and inefficiency.

Example of a Mega Pipeline:
# BAD: 14-step monolith
## Steps
1. Clone repository
2. Install dependencies
3. Run linter
4. Fix lint errors
5. Run type checker
6. Fix type errors
7. Run unit tests
8. Fix failing tests
9. Run E2E tests
10. Fix failing E2E tests
11. Build production bundle
12. Deploy to staging
13. Run smoke tests
14. Promote to production
Improved Approach:
# GOOD: Pipeline that delegates to specialized sub-skills
## Steps
1. Validate environment (clone, install, verify tooling)
2. Run code quality loop (lint + typecheck with auto-fix, max 3 iterations)
3. Run test healing loop (unit + E2E with auto-fix, max 5 iterations)
4. Build and deploy to staging
5. Smoke test and promote to production

This refined pipeline reduces complexity by delegating tasks to specialized sub-skills, resulting in a more manageable and resilient process.

Anti-Pattern: Independent Steps in Sequence

Another frequent mistake is placing independent steps in sequence, which unnecessarily prolongs execution time. If steps don't depend on each other, they should be run in parallel.

Example of Serial Execution:
# BAD: Serial when parallel is possible
1. Run security scan
2. Run performance audit
3. Run accessibility check
4. Generate combined report
Optimized Parallel Execution:
# GOOD: Parallelize independent work
1. Fan-Out: [security scan, performance audit, accessibility check]
2. Aggregate results into combined report

By parallelizing independent tasks, you can significantly reduce execution time while maintaining the same output quality.

Anti-Pattern: Missing Error Context

Without clear error handling, debugging becomes a guessing game. Providing detailed error context can drastically improve the troubleshooting process.

Example of Missing Error Context:
# BAD: No failure guidance
## Steps
1. Parse the config file
2. Validate schema
3. Deploy
Enhanced Error Handling:
# GOOD: Explicit failure handling
## Steps
1. Parse the config file
   - On failure: Report which line has invalid syntax
2. Validate schema
   - On failure: List missing required fields and their expected types
3. Deploy
   - On failure: Capture deploy log, check for common errors (timeout, auth, quota)

Providing specific error messages helps developers quickly identify and resolve issues, improving overall pipeline reliability.

Conclusion

Avoiding pipeline anti-patterns is crucial for maintaining efficient and reliable workflows. By limiting pipeline length, ensuring idempotency, implementing explicit failure handling, and optimizing task execution, you can design pipelines that are both robust and easy to manage. Remember, a well-structured pipeline not only saves time but also enhances the quality and consistency of your software delivery process.

Module 3Pattern 2 -- Branching Router

3.1Dynamic Path Selection

Dynamic Path Selection

In the world of software design, the Branching Router pattern is a powerful tool for directing input to various execution paths, akin to a switch statement in programming. This lesson will guide you through the nuances of implementing a Branching Router, helping you understand when and why to use it, and how it differs from other patterns like the Sequential Pipeline.

When to Use a Branching Router

The Branching Router pattern is ideal in scenarios where:

  • Context-Dependent Handling: A single trigger, such as a slash command or user request, requires different handling based on the context.
  • Multiple Behaviors from One Entry Point: You want to manage multiple behaviors through a single entry point, streamlining your command structure.
  • Diverse Input Types: The inputs vary significantly, necessitating distinct processing paths.

When to Avoid a Branching Router

Consider alternative patterns if:

  • Single Execution Path: If there's only one path to execute, a Sequential Pipeline is more appropriate.
  • Concurrent Execution Needed: If all branches need to be executed simultaneously, opt for a Fan-Out pattern instead.

The Purpose of Routers

Without a Router, managing various content types would require a multitude of specific commands. For instance, instead of having a single /content command, you might end up with /content-guide-create, /content-guide-edit, /content-guide-delete, /content-app-create, /content-news-create, and more. This could easily lead to a bloated command set with over a dozen entries for a single domain. A Router simplifies this by providing a single entry point that intelligently dispatches to the appropriate execution path.

Router vs. Pipeline with Conditionals

Understanding the distinction between a Router and a Pipeline with conditionals is crucial:

  • Pipeline with Conditionals: This involves a sequence of steps where conditional logic is applied within a step. For example:

# Pipeline with conditional (NOT a Router):
  Step 1 -> Step 2 (if X, do A; else do B) -> Step 3 -> Step 4
  # Both paths lead to Step 3.

Here, the process remains sequential, and paths eventually reconverge.

  • Router: In contrast, a Router makes a branching decision upfront, directing input to entirely separate execution paths that do not reconverge:

# Router (IS a Router):
  Input -> analyze type
    -> Path A: completely different steps for guides
    -> Path B: completely different steps for apps
    -> Path C: completely different steps for news
  # Paths do NOT reconverge inside this skill.

If your branches eventually merge back into shared steps, you're dealing with a Pipeline with conditionals, not a Router. It's important to label these structures correctly to ensure clarity for future developers or agents working with the code.

Conclusion

The Branching Router pattern is a strategic approach for managing complex input scenarios with diverse processing needs. By understanding when to use a Router and how it differs from other patterns, you can design more efficient, maintainable systems. Remember, the key is in the initial branching decision that leads to distinct, non-reconverging paths, offering a clean and organized command structure.

3.2The Content Command Router

The Content Command Router

Welcome to the world of efficient content management with the Content Command Router! In this lesson, you'll learn how to streamline your content operations using a single, intelligent command that routes various content types to their appropriate handlers. This approach not only simplifies your command structure but also enhances maintainability and scalability.

Purpose

The Content Command Router serves as a centralized dispatcher for content operations, directing requests to the correct handler based on the specified content type and action. This pattern reduces complexity and redundancy, allowing for a more organized and efficient workflow.

Prerequisites

Before diving into the routing logic, ensure the following conditions are met:

  • The user must provide at least one argument, specifying either the content type or action.
  • For production operations, the user must explicitly confirm by including "prod" in the command.

Routing Logic

The core of the Content Command Router lies in its ability to parse command arguments and route them accordingly. Here's how it works:

Parse Command Arguments

Determine the following from the user's input:

  • Content Type: Options include guide, app, news, or game.
  • Action: Options include create, edit, delete, or list.
  • Target: Options include dev, prod, or both.

Route to Handler

Based on the parsed arguments, the router directs the command to the appropriate handler:

IF type = "guide" AND action = "create":
  -> Execute Guide Creation Pipeline (Pattern 1)
  -> Expects: markdown file path or inline content
  -> Calls: createPrivilegedStructuredGuide mutation
  -> Returns: guide ID, slug, live URL

IF type = "guide" AND action = "edit":
  -> Load existing guide by ID or slug
  -> Apply changes to specified fields
  -> Redeploy with updated content
  -> Returns: updated guide ID, change summary

IF type = "guide" AND action = "delete":
  -> Load existing guide to confirm it exists
  -> Show title and creation date for confirmation
  -> Require explicit "yes" confirmation
  -> Execute deletion with cascade cleanup
  -> Returns: deletion confirmation, cleanup summary

IF type = "app" AND action = "create":
  -> Execute App Scaffolding Pipeline
  -> Expects: app config (name, URL, tech stack, platform)
  -> Calls: createPrivilegedApp mutation
  -> Returns: app ID, live URL

IF type = "news":
  -> Execute News Publishing Pipeline
  -> Expects: headline, content, category, tags
  -> Calls: createPrivilegedNews mutation
  -> Returns: news ID, slug, live URL

IF action = "list":
  -> Query content by type and status
  -> Display formatted table with ID, title, status, date
  -> Returns: content listing

DEFAULT:
  -> Show interactive menu with available options
  -> List valid types: guide, app, news, game
  -> List valid actions: create, edit, delete, list
  -> Show example commands

Constraints

To ensure safe and effective operation, adhere to these constraints:

  • Destructive Actions: Never execute a delete operation without explicit user confirmation.
  • Validation: Always validate the content type before routing.
  • Unknown Types: Provide helpful guidance rather than errors for unknown types.
  • Production Operations: Require the "prod" keyword in the command for any production-related actions.

The Router Advantage

By employing the Router pattern, you consolidate your command structure into a single, intelligent entry point. This approach eliminates the need for multiple separate commands, each with redundant validation logic and inconsistent error handling.

Before the Router

.claude/skills/
  content-create-guide.md
  content-edit-guide.md
  content-delete-guide.md
  content-create-app.md
  content-edit-app.md
  content-delete-app.md
  content-create-news.md
  content-edit-news.md
  content-delete-news.md

Nine files, each requiring separate maintenance and user memorization of distinct command names.

After the Router

.claude/skills/
  content/
    manage.md        # The Router (this file)
    publish.md       # Guide creation pipeline (delegated to)
    app-scaffold.md  # App creation pipeline (delegated to)
    news-publish.md  # News creation pipeline (delegated to)

Four files, one entry point, and consistent validation. The Router efficiently handles dispatching, while sub-skills focus on execution.

Conclusion

The Content Command Router is a powerful tool for developers looking to streamline content management processes. By centralizing command routing, you reduce complexity, improve maintainability, and ensure consistent validation across operations. Embrace this pattern to enhance your workflow and keep your content operations organized and efficient.

3.3Router Design Principles

Router Design Principles

In the world of software development, designing an effective router is crucial for building robust and reliable applications. A well-structured router ensures that commands are executed accurately, minimizing errors and enhancing user experience. This lesson delves into three fundamental principles for crafting efficient routers that prioritize clarity, precision, and maintainability.

1. Route on Data, Not Assumptions

When designing routers, it's essential to base routing decisions on explicit data rather than assumptions. Parsing the actual input allows for precise command execution, reducing the risk of errors. If a command is ambiguous, it's better to seek clarification than to make incorrect assumptions. For instance, if a user intends to edit a guide but the system mistakenly deletes it, the consequences can be severe.

# BAD: Assumes intent
if "guide" in input:
    # Assumes user wants to create a new guide
    create_new_guide()

# GOOD: Parses explicit action
if "type" in input and "action" in input:
    # Routes to the specific handler based on explicit data
    route_to_handler(input["type"], input["action"])
else:
    # Asks for clarification if the command is ambiguous
    print("What would you like to do? [create/edit/delete/list] a [guide/app/news]?")

2. Every Route Must Have a Handler

A comprehensive routing system must include a default path to handle unexpected inputs. Unhandled routes can lead to confusion, prompting the system to improvise responses, which undermines the purpose of having a structured skill set. The default handler should provide guidance, helping users navigate available options.

# BAD: No default handler
if input_type == "guide":
    handle_guide()
elif input_type == "app":
    handle_app()
# What happens when input_type is "tutorial"? The system is left guessing.

# GOOD: Explicit default with guidance
if input_type == "guide":
    handle_guide()
elif input_type == "app":
    handle_app()
elif input_type == "news":
    handle_news()
else:
    print(f"Unknown content type: {input_type}. Available types: guide, app, news.")
    print("Did you mean one of these? [show closest match]")

3. Keep Routing Logic Shallow

Complex routing logic with multiple nested routers can be a sign of poor design. A single level of routing should suffice before handing off to a pipeline or another pattern. Deeply nested routers indicate an overly complex command structure that needs simplification.

# BAD: Nested routers
def route_content():
    route_by_type()
    route_by_action()
    route_by_target()
# Three levels of routing before any work happens

# GOOD: Single router with compound keys
def route_content():
    route_by_type_and_action({
        "guide-create": guide_create_pipeline,
        "guide-edit": guide_edit_pipeline,
        "guide-delete": guide_delete_pipeline_with_confirmation,
        "app-create": app_create_pipeline
    })

Common Mistake: Routing on LLM Interpretation

Leveraging Large Language Models (LLMs) for routing can be powerful but risky. For example, Google's ADK RoutingAgent class uses an LLM to select sub-agents, which can misinterpret commands like "remove that guide about Python" and route them incorrectly. For operations that could lead to data loss, always rely on explicit keywords such as "delete," "remove," or "destroy" rather than LLM interpretations.

Similarly, in Claude Code, the SKILL.md file outlines routing logic that the agent executes. The more explicit your routing conditions, the more reliable your system will be.

Conclusion

By adhering to these principles—routing on data, ensuring every route has a handler, and maintaining shallow routing logic—you can design routers that are both efficient and reliable. Avoiding common pitfalls, such as relying on LLM interpretations for routing, further enhances the robustness of your application. Remember, clarity and precision in routing lead to a smoother user experience and a more maintainable codebase.

Module 4Pattern 3 -- Fan-Out Aggregator

4.1Parallel Execution and Result Merging

Parallel Execution and Result Merging

In the world of software development, efficiency is key. The Fan-Out Aggregator pattern is a powerful technique that allows you to execute multiple independent tasks simultaneously, then seamlessly collect and merge their results. Think of it as the agent equivalent of Promise.all() in JavaScript, designed to optimize your workflow by leveraging parallel execution.

When to Use the Fan-Out Aggregator

The Fan-Out Aggregator pattern shines in scenarios where:

  • Tasks Can Run Concurrently: You have multiple tasks that do not depend on each other and can be executed at the same time.
  • Comprehensive Results Are Required: You need the results from all tasks before you can proceed to the next step in your process.
  • Speed is a Priority: Parallel execution is significantly faster than running tasks sequentially, which can be crucial in time-sensitive applications.

When to Avoid the Fan-Out Aggregator

While powerful, the Fan-Out Aggregator is not always the right choice. Avoid using it when:

  • Tasks Have Dependencies: If the output of one task is required by another, consider using a Sequential Pipeline instead.
  • Only One Result is Needed: If you only need the first successful result, a race pattern might be more appropriate.
  • Resource Constraints Exist: Ensure your system can handle true parallelism without resource bottlenecks.

The Speed Advantage

Consider a scenario where you need to review code for security, performance, and quality. Running these checks sequentially would take three times longer than executing them in parallel. For instance, if each check takes 2 minutes, a sequential approach would take 6 minutes, whereas parallel execution completes in just 2 minutes. Across a team conducting 10 reviews daily, the Fan-Out pattern saves 40 minutes each day. Over a month, this translates to reclaiming 13 hours of valuable developer time.

The Importance of Independence

A critical requirement for the Fan-Out Aggregator is that tasks must be truly independent. This means:

  • No Output Dependencies: If Agent 2 requires the output from Agent 1, they cannot run in parallel.
  • Avoiding Resource Conflicts: Even if tasks do not read each other's output, they must not conflict over shared resources. For example, two agents writing to the same file can lead to merge conflicts, which is a subtle but common mistake.
# BAD: Hidden dependency (both modify the same file)
Fan-Out:
  Agent 1: Add security headers to middleware.ts
  Agent 2: Add rate limiting to middleware.ts
# Both agents read and write middleware.ts -- merge conflict guaranteed

# GOOD: True independence (separate files)
Fan-Out:
  Agent 1: Write security headers to lib/security-headers.ts
  Agent 2: Write rate limiting to lib/rate-limiter.ts
Sequential:
  Agent 3: Import both into middleware.ts

Conclusion

The Fan-Out Aggregator pattern is a robust solution for optimizing task execution through parallelism. By understanding when and how to apply this pattern, you can significantly enhance the efficiency of your development processes. Remember, the key to successful implementation is ensuring task independence and managing resource constraints effectively. Embrace this pattern to unlock new levels of productivity and streamline your workflow.

4.2The Multi-Agent Review Skill

The Multi-Agent Review Skill

In this lesson, you'll learn how to implement the Fan-Out Aggregator pattern in a code review workflow. This pattern allows you to run multiple analysis agents in parallel, each focusing on a specific aspect of the code, and then aggregate their findings into a comprehensive report. This approach not only speeds up the review process but also enhances the quality of the feedback provided to developers.

Overview of the Fan-Out Pattern

The Fan-Out pattern is designed to optimize code review processes by distributing tasks across multiple agents that operate concurrently. Each agent specializes in a particular area of analysis, such as security, performance, or code quality. Once all agents have completed their tasks, their findings are merged into a single, cohesive report.

Prerequisites

Before implementing the Fan-Out pattern, ensure the following prerequisites are met:

  • Target Files or Directories: Clearly specify which files or directories need to be reviewed.
  • Git Diff Availability: For pull request reviews, ensure the git diff is available; otherwise, provide a list of files to be reviewed.
  • No Active Git Operations: Ensure there are no ongoing git operations that could interfere with the review process.

Fan-Out Phase: Running Agents in Parallel

During the Fan-Out phase, multiple agents run in parallel, each focusing on a specific aspect of the code review.

Agent 1: Security Audit

The Security Audit agent focuses on identifying potential security vulnerabilities within the codebase.

  • Scan for Hardcoded Secrets: Detect API keys, tokens, and passwords.
  • Check Authentication Patterns: Identify routes missing authentication checks.
  • Verify Input Validation: Look for SQL injection, XSS, and path traversal vulnerabilities.
  • Flag Dependency Vulnerabilities: Check against known CVEs.
  • Output Format:

{
    "severity": "critical|high|medium|low",
    "file": "string",
    "line": "number",
    "issue": "string",
    "fix": "string"
  }

Agent 2: Performance Analysis

The Performance Analysis agent evaluates the code for performance-related issues.

  • Identify N+1 Query Patterns: Detect inefficient database calls.
  • Check for Missing Indexes: Ensure indexes are present on filtered/sorted fields.
  • Flag Unnecessary Re-renders: Identify missing memoization or unstable references.
  • Measure Bundle Impact: Assess new imports and tree-shaking issues.
  • Output Format:

{
    "severity": "critical|high|medium|low",
    "file": "string",
    "line": "number",
    "issue": "string",
    "fix": "string"
  }

Agent 3: Code Quality

The Code Quality agent ensures adherence to coding standards and best practices.

  • Lint Compliance: Check for adherence to ESLint and Prettier rules.
  • Type Safety Coverage: Identify usage of any types and missing generics.
  • Test Coverage Gaps: Highlight new code lacking tests.
  • Documentation Completeness: Ensure exported functions have JSDoc comments.
  • Output Format:

{
    "severity": "critical|high|medium|low",
    "file": "string",
    "line": "number",
    "issue": "string",
    "fix": "string"
  }

Aggregation Phase: Merging Results

Once all agents have completed their analysis, the results are aggregated into a unified report.

  1. Collect Findings: Gather all results from Agents 1-3.
  2. Deduplicate Issues: Remove overlapping issues identified by multiple agents.
  3. Prioritize by Severity: Sort findings from critical to low severity.
  4. Generate Unified Report: Create a report with sections dedicated to each agent.
  5. Provide Overall Score: Assign a quality score and highlight the top three action items.

Output

The final output of the Fan-Out pattern is a comprehensive review report that includes:

  • Unified Review Report: A consolidated list of findings sorted by severity.
  • Per-Agent Summary: A summary of issues found and time taken by each agent.
  • Overall Quality Score: A score ranging from 0 to 100.
  • Top 3 Recommended Fixes: A list of the most critical fixes, including file paths and line numbers.

Implementing Fan-Out in Claude Code

In Claude Code, you can implement the Fan-Out pattern using the run_in_background: true parameter on Task calls. This allows each agent to run independently, and the orchestrating agent collects the results using TaskOutput.

Example Code

# Launch all three agents in parallel
security_agent = Task(
  subagent="security-reviewer",
  input={"files": diff_files, "focus": "security"},
  run_in_background=True
)

performance_agent = Task(
  subagent="performance-reviewer",
  input={"files": diff_files, "focus": "performance"},
  run_in_background=True
)

quality_agent = Task(
  subagent="quality-reviewer",
  input={"files": diff_files, "focus": "quality"},
  run_in_background=True
)

# Wait for all to complete
security_results = TaskOutput(security_agent, block=True)
performance_results = TaskOutput(performance_agent, block=True)
quality_results = TaskOutput(quality_agent, block=True)

# Aggregate results
combined = merge(security_results, performance_results, quality_results)

Benefits of the Fan-Out Pattern

Before Fan-Out (Sequential Review)

  • Time Taken: Approximately 6 minutes per review.
  • Developer Experience: Developers experience context-switching while waiting for results.

After Fan-Out (Parallel Review)

  • Time Taken: Approximately 2 minutes per review.
  • Developer Experience: All findings are available simultaneously, reducing context-switching and improving efficiency.

Conclusion

The Fan-Out Aggregator pattern is a powerful approach to optimizing code reviews. By leveraging parallel processing, it significantly reduces review time while maintaining high-quality feedback. Implementing this pattern in your workflow can lead to more efficient development cycles and improved code quality. Embrace the power of multi-agent reviews to enhance your team's productivity and codebase integrity.

4.3Aggregation Strategies

Aggregation Strategies

In the world of parallel processing, the "Aggregator" component often presents the greatest challenge. While dispatching tasks concurrently is straightforward, intelligently merging their results is where complexity arises. This lesson explores three effective aggregation strategies to help you intelligently combine outputs from multiple agents. Each strategy has its strengths and weaknesses, making them suitable for different scenarios.

1. Concatenate and Summarize

This strategy involves collecting all outputs and then using a language model to generate a summarized version. It's simple and flexible, making it ideal for exploratory tasks where a high-level overview is sufficient. However, it can be lossy, as important details might be omitted in the summarization process.

### Aggregation: Concatenate and Summarize

1. Gather all outputs from the agents into a single document.
2. Prompt the language model: "Summarize the key findings from these reviews. Highlight the top 5 most important issues across all reviews."
3. Return the generated summary.

# Advantages: 
- Simple and adaptable to unstructured data.
# Disadvantages: 
- Potentially omits critical details.
- Non-deterministic output.

2. Structured Merge

In this approach, each agent produces output in a standardized format, such as JSON or predefined sections. The aggregator then merges these outputs mechanically. This method is precise and ensures all details are preserved, but it requires strict adherence to a schema by all agents.

### Aggregation: Structured Merge

1. Parse each agent's output as a JSON array of findings.
2. Combine all arrays: `all_findings = [...security, ...performance, ...quality]`.
3. Sort findings by severity, prioritizing critical issues.
4. Deduplicate entries: if two findings share the same file and line, retain the one with higher severity.
5. Organize findings into structured report sections.

# Advantages: 
- Deterministic and detail-preserving.
- Facilitates easy filtering.
# Disadvantages: 
- Rigid; requires schema compliance from all agents.

3. Prioritized Filter

This strategy involves each agent scoring its findings, with the aggregator selecting the top N findings across all agents. It's particularly useful in review workflows where the focus is on the most significant issues, regardless of their source.

### Aggregation: Prioritized Filter

1. Each agent assigns a severity score (1-10) to its findings.
2. Combine all findings into a single list.
3. Sort the list by descending score.
4. Select the top 10 findings.
5. Group findings by file for developer convenience.

# Advantages: 
- Directs attention to the most critical issues.
# Disadvantages: 
- May overlook systemic problems (e.g., numerous low-severity issues in one file).

Choosing the Right Strategy

Selecting the appropriate aggregation strategy depends on your specific use case. For code reviews, the Structured Merge is often the best choice, as it ensures every finding is preserved and categorized. In research contexts, where outputs are typically unstructured, Concatenate and Summarize offers greater flexibility. For alerting systems, the Prioritized Filter effectively captures critical issues without excess noise.

Handling Agent Failures

A common pitfall in aggregation is neglecting to address agent failures. If one agent fails while others succeed, your aggregator must manage partial results effectively. Consider the following guidelines:

### Error Handling in Aggregation

- If a single agent fails: Report partial results with a warning and attempt to re-run the failed agent once.
- If multiple agents fail: Abort the process and report which agents failed and the reasons.
- Timeout: If any agent exceeds a 5-minute execution time, cancel it and proceed with the available results.

Conclusion

Mastering aggregation strategies is crucial for efficiently processing parallel tasks. Whether you need a high-level summary, a detailed and structured report, or a prioritized list of critical issues, understanding the strengths and limitations of each approach will empower you to choose the best fit for your needs. By also considering error handling, you ensure robustness in your aggregation processes, enhancing the reliability of your systems.

Module 5Pattern 4 -- Stateful Loop

5.1Iterate Until Done

Iterate Until Done

In this lesson, you'll explore the Stateful Loop pattern, a powerful technique for iterating through a sequence of steps until a specific condition is met. This pattern is particularly useful when the process requires adaptation and learning from previous attempts. By maintaining state between iterations, you can refine your approach dynamically, leading to more efficient and effective solutions.

When to Use the Stateful Loop Pattern

The Stateful Loop pattern is ideal in scenarios where:

  • Success demands multiple attempts, such as testing, fixing, and retesting.
  • The agent needs to iteratively refine its output.
  • You're developing self-healing systems that adapt to changing conditions.
  • The number of iterations required is not predetermined.

When to Avoid the Stateful Loop Pattern

Consider alternative patterns if:

  • The exact number of steps is known in advance, in which case a Sequential Pipeline is more appropriate.
  • There's no meaningful state to maintain between iterations.
  • There's a risk of infinite loops without clear exit conditions.

The Importance of State

State is what differentiates a simple repetitive loop from an adaptive, intelligent process. A loop without state merely repeats the same action, yielding the same results each time. In contrast, a stateful loop leverages information from previous iterations to modify its approach, making it more effective.

Example: Stateless vs. Stateful Loop

Stateless Loop (Ineffective)

# Stateless loop (BAD - does the same thing each time):
REPEAT 5 times:
  Run tests
  Fix failures

This approach blindly repeats the same actions, potentially applying the same incorrect fix multiple times without learning from past attempts.

Stateful Loop (Effective)

# Stateful loop (GOOD - learns from each iteration):
State: { attempt: 0, previous_fixes: [], remaining_failures: [] }
REPEAT until tests pass OR attempt >= 5:
  Run tests
  Compare failures to previous iteration
  If same failures persist after fix: try a DIFFERENT approach
  Record fix in previous_fixes (avoid repeating)
  Increment attempt

The stateful loop tracks what has been tried and adapts accordingly, avoiding the pitfall of repeating ineffective solutions.

Real-World Analogy

Consider a doctor diagnosing a patient. The initial appointment results in a treatment hypothesis. If the treatment fails, the doctor doesn't simply repeat it. Instead, they revise their hypothesis based on new information and try a different approach. Each visit builds on the patient's history, much like how a stateful loop evolves with each iteration.

Conclusion

The Stateful Loop pattern is a robust tool for scenarios requiring iterative refinement and adaptation. By maintaining state across iterations, you can dynamically adjust your approach, leading to more effective problem-solving. Remember, the key to success with stateful loops is leveraging past information to inform future actions, much like a doctor refining a diagnosis with each patient visit.

5.2The Self-Healing Test Skill

The Self-Healing Test Skill

In the realm of automated testing, the self-healing test skill is a game-changer. Leveraging Playwright's AI test agents, this pattern empowers your testing suite to autonomously diagnose, fix, and re-run tests until all pass. This lesson will guide you through implementing a self-healing test runner, enhancing your development workflow by reducing manual intervention and accelerating feedback loops.

Self-Healing Test Runner

Objective: Automate the process of running tests, diagnosing failures, applying fixes, and re-running tests until success is achieved.

State Management

To effectively manage the self-healing process, maintain the following state variables:

  • attempt_count: Tracks the number of test iterations.
  • max_attempts: Limits the number of attempts to prevent infinite loops.
  • failures: Stores details of current test failures.
  • fixes_applied: Records the fixes applied during each iteration.
  • files_modified: Lists files that have been altered.

Prerequisites

Before implementing the self-healing test runner, ensure:

  • A test framework is installed and configured.
  • The source code is accessible.
  • The Git repository is in a clean state, allowing for easy reversion of changes if necessary.

The Self-Healing Loop

The core of the self-healing test runner is a loop that continues until all tests pass or the maximum number of attempts is reached.

# Pseudocode for Self-Healing Test Loop

WHILE attempt_count < max_attempts AND failures exist:

  1. **Run Test Suite**
     - Execute: `npm run test:safe`
     - Capture stdout, stderr, and exit code.
     - Parse output to determine pass/fail counts.

  2. **Analyze Failures**
     - Extract failing test names and error messages from the output.
     - Read the test and source code files.
     - Diagnose root causes:
       a. Test bug (e.g., incorrect selector, outdated snapshot, timing issue)
       b. Source bug (e.g., logic error, missing null check, incorrect return type)
       c. Environment bug (e.g., missing environment variable, port conflict, stale cache)
     - If a persistent failure occurs with the same fix, escalate by trying a fundamentally different approach.

  3. **Apply Fix**
     - Address test bugs by updating expectations or selectors.
     - Resolve source bugs by correcting the code.
     - Fix environment bugs by cleaning caches, restarting services, or updating configurations.
     - Document changes in `fixes_applied`:
       `{ file, line, old_code, new_code, reason }`
     - Add modified files to `files_modified`.

  4. **Update State**
     - Increment `attempt_count`.
     - Re-run only the previously failing tests for quicker feedback.
     - Update the `failures` list.
     - Compare with the previous iteration:
       - New failures indicate a regression.
       - Same failures suggest the need for a different approach.
       - Fewer failures signify progress.

  5. **Check Termination**
     - IF all tests pass: EXIT with a success report.
     - IF `attempt_count` >= `max_attempts`: EXIT with a failure report.
     - IF no progress in the last two iterations: EXIT with a stuck report.
     - ELSE: CONTINUE the loop.

Output

Upon completion, the self-healing test runner provides a comprehensive report:

  • Total number of attempts.
  • Detailed list of fixes applied, including file, line, and change description.
  • Final test status, indicating pass/fail counts.
  • Remaining failures if the maximum attempts are reached.
  • A Git diff of all changes made during the process.

Key Insight

Each iteration of the self-healing loop builds upon the previous one. The agent retains knowledge of past failures and applied fixes, avoiding redundant efforts and improving efficiency.

Before Self-Healing Tests (Manual Cycle)

Developer runs tests -> sees 3 failures -> fixes 1 -> runs again ->
sees 2 failures (one new!) -> fixes 1 -> runs again -> sees 1 failure ->
fixes it -> runs again -> all pass. Total: 15 minutes, 4 manual cycles.

After Self-Healing Tests (Automated Loop)

Agent runs tests -> sees 3 failures -> fixes all 3 -> runs again ->
sees 1 regression -> fixes it -> runs again -> all pass.
Total: 3 minutes, 3 automated cycles. Developer did nothing.

The time savings are significant. By automating the test repair process, development teams can save hours each day, especially when running self-healing tests on every pull request.

Conclusion

The self-healing test skill is a powerful tool in the developer's arsenal, transforming the way automated tests are managed. By continuously learning from past iterations and autonomously applying fixes, this pattern not only saves time but also enhances the reliability of your codebase. Implementing a self-healing test runner can lead to more efficient development cycles and a more robust application. Embrace this pattern to elevate your testing strategy and streamline your workflow.

5.3Loop Safety and Exit Conditions

Loop Safety and Exit Conditions

In the realm of stateful loops, vigilance is key. These loops, while powerful, can inadvertently spiral into infinite cycles, consuming resources and time. This lesson will equip you with essential safety mechanisms to prevent such scenarios, ensuring your loops are both effective and controlled. We'll explore three critical safeguards: setting iteration limits, detecting progress, and enforcing scope constraints.

1. Hard Cap on Iterations

A hard cap on iterations is your first line of defense against infinite loops. By defining a maximum number of attempts, you prevent the loop from running endlessly. A typical default is five attempts, which suits most fix-iterate workflows. If a problem persists beyond ten attempts, it's a signal for human intervention.

# Explicit hard cap
## State
max_attempts = 5  # NEVER exceed this

## Termination
if attempt_count >= max_attempts:
    print("Max attempts reached. Stopping process.")
    # Report remaining failures
    exit()

Insight:

Setting a clear iteration limit not only prevents resource wastage but also provides a structured approach to problem-solving. It encourages early detection of issues that require human insight.

2. Progress Detection

Progress detection is crucial to avoid redundant operations. If an iteration yields the same failures as the previous one with an identical fix, the loop is stuck. This mechanism is often overlooked, yet it's vital to prevent repetitive, ineffective actions.

# Progress detection
## In Step 4 (Update State)
if current_failures == previous_failures and last_fix == previous_fix:
    print("Stuck: same failures after same fix. Need human review.")
    exit()
elif len(current_failures) > len(previous_failures):
    print("Regression detected. Reverting last fix.")
    # Revert last fix and try a different approach

Insight:

By actively monitoring progress, you can swiftly identify when the loop is no longer making headway, allowing for timely intervention and alternative strategies.

3. Scope Limits

Scope limits ensure that your loop only modifies files it is explicitly allowed to change. Without these constraints, a loop can become a runaway process, altering unrelated files and causing collateral damage.

# Scope limits
## Constraints
modifiable_files = get_modifiable_files()  # Defined in step 2 analysis

if file not in modifiable_files:
    print(f"Modification not allowed on {file}.")
    exit()

# Additional constraints
if file in ['package.json', 'tsconfig.json']:
    print("Modification of configuration files is prohibited.")
    exit()

Insight:

Defining an allowlist of modifiable files protects your codebase from unintended alterations, maintaining the integrity of your project.

Common Mistake: No Revert Capability

A robust loop should include a revert capability. If a loop exacerbates the problem, you need a mechanism to undo changes. Tracking every modification—old code, new code, file, and line—enables a full revert. Working on a separate git branch offers an additional safety net, allowing you to restore the original state with git checkout ..

Insight:

Incorporating a revert mechanism not only safeguards against errors but also fosters a culture of experimentation and learning, as developers can confidently test solutions knowing they can easily backtrack.

Conclusion

Stateful loops, when managed with care, are powerful tools in a developer's arsenal. By implementing hard iteration caps, progress detection, and scope limits, you can harness their potential while mitigating risks. Remember, the goal is not just to fix issues but to do so efficiently and safely. With these strategies, you'll be well-equipped to handle loops with confidence and precision.

Module 6Pattern 5 -- Delegation Chain

6.1Hierarchical Task Decomposition

Hierarchical Task Decomposition

In the world of software development, tackling complex tasks often requires breaking them down into manageable components. This is where the Delegation Chain pattern shines. By decomposing a complex task into subtasks and delegating each to a specialized sub-agent or sub-skill, you can streamline your workflow and enhance efficiency. This lesson will guide you through the intricacies of the Delegation Chain pattern, providing you with the knowledge to implement it effectively in your projects.

When to Use the Delegation Chain Pattern

The Delegation Chain pattern is particularly useful in scenarios where:

  • Complexity Overwhelms a Single Skill: When a task's complexity exceeds the capabilities of a single skill, breaking it down becomes essential.
  • Diverse Expertise is Required: Different subtasks may require distinct areas of expertise, necessitating specialized agents.
  • Composing Larger Workflows: If you aim to integrate existing skills into broader workflows, delegation is key.
  • Decision-Making Between Delegations: When the orchestrating agent must make decisions about which sub-agent to engage next or how to handle outputs, delegation is beneficial.

When to Avoid the Delegation Chain Pattern

While powerful, the Delegation Chain pattern is not always the best choice. Avoid it in cases where:

  • Simplicity Suffices: If a task is straightforward enough for a single skill, avoid over-engineering with delegation.
  • Tight Coupling is Necessary: When subtasks require tight coupling or shared state, a single Pipeline might be more appropriate.
  • Minimal Subtasks Exist: If there are fewer than three distinct subtasks, the overhead of delegation may not be justified.

The Rationale Behind Delegation

Consider the development of a full-stack feature, such as a user profile editing page. This task involves multiple components: database schema changes, API mutations, React components, form validation, tests, and documentation. Each of these requires different skills and contexts. A backend developer needs to understand database schemas, while a frontend developer focuses on React patterns. A test engineer, on the other hand, must be proficient with tools like Playwright.

Attempting to load all this context into a single skill results in a bloated and unfocused approach. Delegation allows each sub-agent to operate within its specialized context, ensuring efficiency and clarity. The architect agent handles requirements, the backend agent manages schema specifications, and the frontend agent deals with component specifications. Each agent works within its domain, contributing to a cohesive whole.

The Role of the Orchestrator

In a Delegation Chain, the parent agent, or orchestrator, plays a crucial role. It doesn't perform the tasks directly but makes strategic decisions about the workflow. This includes:

  • Agent Invocation: Determining which agent to call upon next.
  • Output Evaluation: Assessing whether the output from one agent is ready to be passed to the next.
  • Error Handling: Deciding whether to retry a failed delegation or abort the process.

This decision-making capability distinguishes the Delegation Chain from a simple script that sequentially calls functions. The orchestrator adapts to changing conditions, ensuring a flexible and responsive workflow.

# Script (no intelligence):
run(backend_agent)
run(frontend_agent)
run(test_agent)

# Delegation Chain (adaptive):
spec = run(architect_agent)
if spec.has_gaps:
    spec = run(architect_agent, feedback=spec.gaps)  # Retry with feedback
backend = run(backend_agent, input=spec.backend_part)
frontend = run(frontend_agent, input=spec.frontend_part)
if frontend.has_type_errors:
    frontend = run(frontend_agent, input=spec + type_errors)  # Fix with context
run(test_agent, input=[backend.files, frontend.files])

Conclusion

The Delegation Chain pattern offers a robust framework for managing complex tasks by leveraging the strengths of specialized sub-agents. By understanding when to use this pattern and how to implement it effectively, you can enhance your development process, ensuring that each component of your project is handled by the most suitable expertise. Embrace the power of delegation to create efficient, adaptable workflows that meet the demands of modern software development.

6.2The Full-Stack Feature Skill

The Full-Stack Feature Skill

In this lesson, you'll learn how to leverage the Delegation Chain pattern to efficiently build a complete full-stack feature from specification to deployment. By orchestrating specialized agents, you can streamline the development process, ensuring that each component of your application is crafted with precision and expertise.

Prerequisites

Before diving into the delegation process, ensure you have the following:

  • A clear set of feature requirements (user stories, acceptance criteria)
  • Access to the project codebase
  • All necessary dependencies installed
  • A clean git state on the main branch

Delegation Flow

1. Delegate to Architect Agent

Input: Feature requirements from the user Task: Design the data schema, API surface, and component hierarchy Output: A comprehensive technical specification document, including:
  • Convex schema additions (tables, indexes, fields)
  • Mutation and query function signatures
  • React component tree with props
  • Page routing additions
Evaluation: Ensure the specification covers all acceptance criteria. If any gaps are identified, provide specific feedback to the Architect Agent for revisions.

2. Evaluate Architect Output

  • Review the specification for completeness against the acceptance criteria.
  • Verify the schema design for completeness and correctness (no missing fields, correct types, defined indexes).
  • Check the API design to ensure all CRUD operations are covered and authentication checks are specified.
  • Assess the component design for responsiveness, accessibility, and alignment with the design system.
  • If gaps are found, return to the Architect with detailed feedback. If complete, proceed to parallel implementation.

3. Delegate to Implementation Agents (Fan-Out)

a. Backend Agent

Input: Schema and API specification from the Architect Task: Develop Convex schema additions, mutations, queries, and validators Constraints: Adhere to existing patterns in the convex/ directory and follow Convex best practices Output: Backend files ready for testing Expected Files: convex/[feature].ts, updates to convex/schema.ts

b. Frontend Agent

Input: Component hierarchy and API specification from the Architect Task: Create React components, hooks, and page routes Constraints: Utilize the existing design system (cn(), shadcn components) and follow app/ directory conventions Output: Frontend files ready for testing Expected Files: app/[route]/page.tsx, components/[feature]/*.tsx, hooks/use-[feature].ts

c. Test Agent

Input: Full specification from the Architect, plus file paths from Backend and Frontend agents Task: Write end-to-end (E2E) tests covering acceptance criteria and unit tests for business logic Constraints: Use Playwright for E2E tests and mock authentication with the mockAuthentication helper Output: Test files covering key flows Expected Files: __tests__/e2e/[feature].spec.ts, __tests__/unit/[feature].test.ts

4. Delegate to Integration Agent

Input: All file paths from step 3 agents Task: Integrate the frontend with the backend (imports, hooks, type alignment) and resolve type errors Output: A fully integrated, compilable codebase (ensure npm run typecheck passes) Note: If type errors persist after the first pass, re-run with error output for further debugging.

5. Delegate to QA Agent (Stateful Loop)

Input: Integrated codebase (all file paths) Task: Execute tests, fix any failures, and iterate (maximum of 5 attempts) Output: All tests passing and a QA report with coverage details

6. Final Review

  • Confirm that all acceptance criteria are met.
  • Execute a full build (npm run build).
  • Verify there are no TypeScript errors (npm run typecheck).
  • Compile a report detailing files created, tests passed, and a summary of the feature.

Conclusion

The Delegation Chain pattern is a powerful meta-pattern that orchestrates other patterns to efficiently build full-stack features. By breaking down tasks into specialized roles, you can enhance focus, reduce context-switching, and produce clean, reviewable code. This method not only improves the quality of your codebase but also accelerates the development process, making it a valuable strategy for any development team. Embrace the power of delegation to transform your approach to building robust, scalable applications.

6.3Delegation Boundaries and Context Management

Delegation Boundaries and Context Management

In the realm of software development, effective delegation is key to managing complex projects. However, the challenge often lies in managing context when delegating tasks to sub-agents. Each sub-agent operates within its own context window, and the parent agent must make critical decisions about:

  • What context to pass down: Providing too much information can overwhelm the child agent, while too little can lead to errors or incomplete work.
  • What results to pass up: The parent agent doesn't need every detail of the child's work. Instead, it requires a concise summary and relevant file paths.
  • When to intervene: If a child agent encounters difficulties, should the parent agent step in or offer additional guidance?

Let's explore three guiding principles to navigate these challenges effectively.

1. Pass Specifications, Not Code

When delegating tasks, it's crucial to provide child agents with clear specifications rather than overwhelming them with existing code. This approach allows them to focus on what needs to be built without confusion.

# BAD: Passing code as context
Delegate to Frontend Agent:
  Input: "Here is the entire backend file (300 lines). Build a UI for it."
  # The agent wastes its context window on unnecessary code.

# GOOD: Passing specs as context
Delegate to Frontend Agent:
  Input: "Build a profile editor using these API endpoints:
    - GET /api/profile: returns { name, email, bio, avatar }
    - PUT /api/profile: accepts { name, bio, avatar }
    Use the existing form components from components/ui/form.tsx"
  # The agent can refer to form.tsx if needed, starting with a clear spec.

2. Collect Paths, Not Contents

Once a child agent completes its task, gather the list of files created or modified rather than the full content. This prevents the parent's context from becoming cluttered with unnecessary details.

# BAD: Child returns full file contents
Backend Agent Output:
  "I created convex/profile.ts with the following code: [300 lines]"
  # The parent's context is unnecessarily filled with 300 lines of code.

# GOOD: Child returns file paths and summary
Backend Agent Output:
  "Created:
    - convex/profile.ts (3 mutations, 2 queries, 1 validator)
    - Updated convex/schema.ts (added profiles table with 5 fields, 2 indexes)
  All mutations require authenticated userId."
  # The parent passes these paths to the next agent.

3. Define Handoff Contracts

Clear and specific handoff contracts are essential for successful delegation. Each task should define what is expected in terms of input, output, and format.

# BAD: Vague handoff
"Build the frontend for the profile feature."
# Lacks details on the feature, specifications, components, and completion criteria.

# GOOD: Contract-based handoff
"Build the profile editor page.
  Input: API spec (convex/profile.ts, see mutations: updateProfile, queries: getProfile)
  Components: Use shadcn Form, Input, Textarea, Button from components/ui/
  Route: app/(main)/profile/edit/page.tsx
  Requirements: Form validation, loading states, error handling, success toast
  Output: List of files created, confirmation that TypeScript compiles"

Context Budget Rule of Thumb

A sub-agent should receive no more than 2,000 tokens of context from its parent. If more context is needed, the task should be broken down further to ensure clarity and manageability.

In Google's ADK, this approach aligns with AgentTeam compositions, where a manager agent delegates tasks to specialist agents. This pattern is consistent across various frameworks, with the primary challenge being the decision of what to pass down and what to collect back.


By adhering to these principles, you can streamline the delegation process, ensuring that each agent operates efficiently within its context window. This not only enhances productivity but also minimizes errors, leading to more successful project outcomes.

Module 7Composing Patterns and Building Your Skill Library

7.1Pattern Composition Rules

Pattern Composition Rules

In the realm of software development, real-world skills seldom rely on a single design pattern. Instead, the most effective solutions often involve the strategic composition of multiple patterns. However, successful pattern composition requires adherence to certain rules to ensure efficiency and maintainability.

Safe Compositions

When combining patterns, some compositions are considered safe and effective. These combinations leverage the strengths of each pattern while minimizing potential downsides:

  • Router -> Pipeline: First, determine the appropriate pipeline using a router, then execute the pipeline. This ensures tasks are directed to the correct process flow.
  • Delegation -> Fan-Out: Delegate tasks to different components, then parallelize the execution of sub-tasks. This approach can efficiently handle multiple tasks concurrently.
  • Pipeline -> Loop: Execute the steps in a pipeline, then iterate over any failures. This allows for systematic error handling and retry mechanisms.
  • Delegation -> Pipeline + Loop: Delegate tasks to agents that utilize both pipelines and loops. This composition is effective for complex workflows requiring iterative processing.
  • Router -> Delegation: Use a router to direct tasks to different orchestrators based on their complexity, ensuring that each task is handled by the most suitable process.

Dangerous Compositions

Certain pattern combinations can lead to inefficiencies and resource issues. These compositions should be approached with caution:

  • Loop -> Loop: Nesting loops can exponentially increase iteration counts, leading to performance bottlenecks. For example, a 5 x 5 nested loop results in 25 iterations, which can be resource-intensive.
  • Router -> Router: Recursive routing can lead to complex and unmanageable flows. It's often better to consolidate into a single router.
  • Fan-Out -> Fan-Out: This can result in exponential parallelism, risking resource exhaustion. It's crucial to manage parallel tasks carefully to avoid overwhelming the system.
  • Loop -> Fan-Out: Each iteration spawning parallel agents can cause a resource explosion, making it difficult to control and monitor system performance.

Why Nested Loops Are Dangerous

Consider the following example of nested loops:

# DANGEROUS: Nested loops
Outer Loop (max 5): For each failing module
  Inner Loop (max 5): Fix tests in this module until passing

# Worst case: 5 * 5 = 25 iterations
# Each iteration may run tests + apply fixes
# Total: 25 test runs + 25 fix attempts = significant time and API cost

# SAFER: Single loop with batched fixes
Loop (max 8): Fix all failing tests across all modules
  Run full test suite
  Fix the top 3 failures (batch approach)
  Repeat until all pass or max reached

# Worst case: 8 iterations with batch fixes
# More efficient and easier to track progress

In the safer approach, a single loop with batched fixes reduces the number of iterations and simplifies progress tracking.

The Composition Test

A practical way to assess the complexity of your pattern composition is the "whiteboard test." If you cannot sketch your skill's execution flow on a whiteboard in under 60 seconds, it is likely too complex and should be decomposed into simpler components.

Visual Test for Composition Complexity

# GOOD: Can sketch in 30 seconds
Router -> Pipeline A (5 steps)
       -> Pipeline B (4 steps)
       -> Pipeline C (3 steps)

# ACCEPTABLE: Can sketch in 60 seconds
Delegation -> Architect (Pipeline: 3 steps)
           -> Fan-Out: [Backend, Frontend, Tests]
           -> Integration (Pipeline: 2 steps)
           -> QA (Loop: max 5 iterations)

# TOO COMPLEX: Cannot sketch clearly
Delegation -> Router -> Pipeline -> Loop -> Fan-Out -> Loop -> Router
# What is this even doing? Decompose into smaller skills.

Conclusion

Mastering pattern composition is crucial for building efficient and maintainable software solutions. By understanding which compositions are safe and which are risky, you can design systems that are both powerful and manageable. Remember, simplicity is key—if a composition is too complex to explain or visualize quickly, it's time to break it down into more digestible parts. Embrace these guidelines to enhance your skill library and create robust, scalable applications.

7.2Building a Skill Library That Scales

Building a Scalable Skill Library

Creating a robust and scalable skill library is essential for managing and deploying a large number of skills efficiently. Drawing from the experience of developing over 80 skills, this guide outlines the organizational principles that have proven effective in real-world applications.

Directory Structure

Organizing your skills into a clear directory structure is crucial for scalability and maintainability. Here's a recommended structure:

.claude/skills/
  common/            # Shared sub-skills used by multiple domains
    validate.md      # Input validation (Sequential Pipeline)
    confirm.md       # User confirmation prompt
    report.md        # Standardized output formatting
  content/           # Content creation and management
    publish.md       # Sequential Pipeline
    review.md        # Fan-Out Aggregator
    manage.md        # Branching Router
    enhance.md       # Stateful Loop (AI enhancement iterations)
  deploy/            # Deployment skills
    production.md    # Sequential Pipeline
    rollback.md      # Sequential Pipeline
    canary.md        # Pipeline + Loop (deploy, monitor, expand or rollback)
  testing/           # Test-related skills
    heal.md          # Stateful Loop
    coverage.md      # Sequential Pipeline
    generate.md      # Delegation Chain (plan -> generate -> heal)
  features/          # Feature implementation
    full-stack.md    # Delegation Chain
    component.md     # Sequential Pipeline
    api-endpoint.md  # Sequential Pipeline

Key Takeaways:

  • Common Directory: Use the common/ directory for sub-skills that are shared across multiple domains, promoting reuse and reducing duplication.
  • Domain-Specific Directories: Organize skills by domain (e.g., content/, deploy/) to streamline navigation and management.

Naming Conventions

Adopting consistent naming conventions enhances clarity and usability:

  • Skill File Names: Use verbs or verb phrases to describe the action performed by the skill, such as publish.md or review.md.
  • Directory Names: Use nouns to represent the domain, such as content/ or testing/.
  • Avoid Generic Names: Names like do-thing.md are uninformative. Be specific to convey the skill's purpose.

Example:

# Pattern: Sequential Pipeline
# Domain: Deployment
# Last updated: 2026-03-15

# Deploy to Production
...

Reuse Over Duplication

To maintain a clean and efficient skill library, prioritize reuse:

  • Extract Shared Steps: If multiple skills share common steps, extract these into a separate sub-skill and reference it.
  • Cross-Reference: Use comments to guide users to the shared sub-skill.

Example:

# BAD: Validation duplicated in 5 skills
# publish.md: "1. Check frontmatter 2. Validate modules 3. Check lengths"
# review.md:  "1. Check frontmatter 2. Validate modules 3. Check lengths"
# enhance.md: "1. Check frontmatter 2. Validate modules 3. Check lengths"

# GOOD: Extracted to common/validate.md
# publish.md: "1. Run validation skill (see .claude/skills/common/validate.md)"
# review.md:  "1. Run validation skill (see .claude/skills/common/validate.md)"
# enhance.md: "1. Run validation skill (see .claude/skills/common/validate.md)"

Versioning and Evolution

Skills evolve over time. Implement versioning to track changes effectively:

  • Changelog Comments: Document significant changes within the skill file.
  • Update References: When a skill's behavior changes, update all referencing skills to ensure consistency.

Example:

# Deploy to Production
# v3 (2026-03-15): Added health check timeout (was missing, caused false positives)
# v2 (2026-02-20): Added bundle size check before deploy
# v1 (2026-01-10): Initial version

Library Size Guidelines

As your skill library grows, adjust your organizational strategy accordingly:

  • Under 20 Skills: A flat structure is manageable.
  • 20-50 Skills: Introduce domain directories for better organization.
  • 50-100 Skills: Utilize a common/ directory for shared sub-skills.
  • 100+ Skills: Consider implementing namespacing (e.g., team/domain/skill) and maintaining a registry file for easy access.

Conclusion

Building a scalable skill library requires thoughtful organization, consistent naming conventions, and a focus on reuse. By following these principles, you can create a maintainable and efficient library that supports growth and adaptation over time. Remember, the key to success is in the details—organize meticulously, name with purpose, and always strive for clarity and reuse.

7.3From Google ADK to Your Own Framework

From Google ADK to Your Own Framework

In the rapidly evolving landscape of agent frameworks, understanding the underlying patterns is more valuable than mastering any single tool. Whether you're working with Google's ADK, Claude Code's SKILL.md, LangChain's tools, or CrewAI's tasks, the core patterns remain consistent. This lesson will guide you through translating these patterns across different frameworks, empowering you to adapt quickly to new tools and enhance your skill library.

Understanding Framework Patterns

Agent frameworks often implement a set of foundational patterns. Recognizing these patterns allows you to transition seamlessly between different frameworks. Here's how these patterns map across popular frameworks:

| Pattern | Google ADK | Claude Code | LangChain | CrewAI |

|---------------------|-------------------|-----------------|-----------------|-----------------|

| Sequential Pipeline | SequentialAgent | Steps in SKILL.md | SequentialChain | Process.sequential |

| Branching Router | RoutingAgent | IF/ELSE in SKILL.md | RouterChain | Custom routing |

| Fan-Out Aggregator | ParallelAgent | run_in_background | MapReduceChain | Process.hierarchical |

| Stateful Loop | LoopAgent | WHILE in SKILL.md | WhileLoop | Task with retry |

| Delegation Chain | AgentTeam | Sub-skill references | AgentExecutor | Crew with agents |

Google ADK: Explicit Pattern Classes

Google ADK offers explicit support for each pattern through dedicated classes. This approach simplifies the implementation of complex workflows but can be rigid, as it requires your skills to fit predefined classes.

# Google ADK: Explicit pattern classes
from google.adk.agents import SequentialAgent, ParallelAgent, LoopAgent

deploy_pipeline = SequentialAgent(
    name="deploy",
    sub_agents=[test_agent, build_agent, deploy_agent, verify_agent]
)

review_fanout = ParallelAgent(
    name="review",
    sub_agents=[security_agent, performance_agent, quality_agent]
)

fix_loop = LoopAgent(
    name="fix",
    sub_agent=test_and_fix_agent,
    max_iterations=5
)

Claude Code: Flexibility with SKILL.md

Claude Code provides unparalleled flexibility by allowing you to define patterns in free-form markdown. This freedom enables creative solutions but requires careful structuring to ensure correctness, as there's no built-in validation.

# Claude Code: Pattern expressed in markdown
## Loop (Stateful)
WHILE tests_failing AND attempt < 5:
  1. Run tests
  2. Analyze failures
  3. Apply fix
  4. Update state

LangChain: Structured Composition

LangChain strikes a balance between structure and flexibility. You compose patterns programmatically, allowing for dynamic construction while maintaining a degree of structure.

CrewAI: Focus on Delegation

CrewAI emphasizes the Delegation pattern, organizing workflows as a Crew of Agents with Tasks. While other patterns like Pipelines and Loops are present, they are embedded within tasks rather than highlighted as primary concepts.

Key Insight: Master Patterns, Not Frameworks

The true skill lies in understanding the patterns rather than the frameworks themselves. As new agent frameworks emerge, your familiarity with these patterns will allow you to adapt quickly, with only the syntax being new.

Practical Exercise: Building Your SKILL.md

To solidify your understanding, try this exercise:

  1. Review Your Workflow: Identify a repetitive task you perform, such as deployment or code review.
  2. Pattern Identification: Determine which of the five patterns your task follows.
  3. Write a SKILL.md: Document the task in a SKILL.md format, including Purpose, Prerequisites, Steps, Constraints, and Output.
  4. Enhance with Pattern Elements: Add specific elements like exit conditions for loops or routing tables for routers.
  5. Save and Execute: Save your SKILL.md to .claude/skills/[domain]/[verb].md and run it.
  6. Evaluate and Iterate: Compare the automated approach to your manual process and refine as needed.

By investing 20 minutes in writing your first SKILL.md, you'll save time with each subsequent use. By the tenth iteration, you'll wonder how you managed without it.

Conclusion

Understanding and applying these core patterns across different frameworks will not only enhance your current workflows but also prepare you for future innovations in agent technology. Embrace pattern thinking, and you'll be equipped to tackle any framework that comes your way.

Module 8Reference -- Pattern Selection Cheat Sheet

8.1Decision Matrix

Decision Matrix

Navigating the world of design patterns can be daunting, especially when you're unsure which pattern best fits your needs. This guide will walk you through a series of questions to help you determine the most suitable pattern for your specific scenario. By the end of this lesson, you'll have a clearer understanding of how to select and apply design patterns effectively.

Step-by-Step Pattern Selection

Q1: How Many Independent Tasks Are There?

  • One task with ordered steps: Opt for a Sequential Pipeline. This pattern is ideal when your task involves a series of steps that must be executed in a specific order.
  • One task with conditional paths: Use a Branching Router. This pattern is perfect when your task can take different paths based on certain conditions.
  • Multiple independent tasks: Choose a Fan-Out Aggregator. This pattern allows you to handle several tasks concurrently, aggregating their results as needed.

Q2: Do You Know How Many Iterations You Need?

  • Yes, exactly N steps: Stick with a Sequential Pipeline. When you know the exact number of iterations, this pattern ensures each step is executed in sequence.
  • No, iterate until success: Implement a Stateful Loop. This pattern is useful when the number of iterations is unknown and depends on achieving a successful outcome.

Q3: Is the Task Too Complex for One Agent?

  • No, one agent can handle it: Refer back to patterns 1-4 based on your previous answers.
  • Yes, needs multiple specialists: Consider a Delegation Chain. This pattern is effective when a task requires the expertise of multiple specialists, each handling a specific part of the process.

Q4: Does the Same Entry Point Need Different Behaviors?

  • Yes: A Branching Router should be your outer pattern. This allows for different behaviors based on the input while maintaining a unified entry point.
  • No: Choose the appropriate pattern based on your answers to Q1-Q3.

Extended Decision Scenarios

To further illustrate these concepts, let's explore some common scenarios and the corresponding pattern selections:

| Scenario | Questions Path | Pattern |

|----------|----------------|---------|

| "Deploy the app" | Q1: one task, ordered -> Q2: yes, 5 steps | Sequential Pipeline |

| "Handle user input: might be text, image, or code" | Q4: yes, different behaviors | Branching Router |

| "Run security + performance + accessibility checks" | Q1: three independent tasks | Fan-Out Aggregator |

| "Fix tests until they pass" | Q2: no, unknown iterations | Stateful Loop |

| "Build a complete feature from scratch" | Q3: yes, needs architect + devs + QA | Delegation Chain |

| "Deploy, but retry on failure" | Q1: one task -> Q2: might need retry | Pipeline + Loop (compose) |

| "Route to correct pipeline, then run it" | Q4: yes -> Q1: ordered steps per route | Router + Pipeline (compose) |

When Two Patterns Seem Equally Valid

In some cases, you might find that two patterns could potentially fit your task. Here's how to decide:

  • Complexity as a Tiebreaker: If implementing a task as a Pipeline would result in fewer than 30 lines of code, stick with the Pipeline. If it exceeds 50 lines, consider using a Delegation Chain.
  • Simple Logic vs. Over-Patterning: A simple 2-branch Router might just be an IF statement within a Pipeline. Avoid over-complicating your design with unnecessary patterns. Patterns should simplify complexity, not add to it.

Practical Examples

# Example of a simple conditional in a Pipeline:
def process_input(input_data):
    # Step 1: Parse input
    if input_data.type == 'markdown':
        # Step 2: Convert markdown to HTML
        converted_data = convert_to_html(input_data)
    else:
        # Step 2: Use HTML as-is
        converted_data = input_data
    # Step 3: Deploy to database
    deploy_to_database(converted_data)

# Example where a Router is necessary:
def route_input(input_data):
    if input_data.type == 'guide':
        # 5-step publishing pipeline with metadata generation
        process_guide(input_data)
    elif input_data.type == 'app':
        # 3-step scaffolding pipeline with embed URL validation
        process_app(input_data)
    elif input_data.type == 'news':
        # 4-step news pipeline with category tagging
        process_news(input_data)

Conclusion

Selecting the right design pattern is crucial for efficient and maintainable code. By following this decision matrix, you can systematically evaluate your task requirements and choose the most appropriate pattern. Remember, the goal is to manage complexity, not to create it. Use patterns as tools to streamline your development process, and don't hesitate to adapt them to fit your unique needs. Happy coding!

8.2Quick Reference Card

Quick Reference Card

Welcome to the "Pattern Selection Cheat Sheet," your go-to guide for understanding and implementing key architectural patterns in agent systems. This quick reference card will help you choose the right pattern for your needs, ensuring robust and efficient workflows. Let's dive into the essential patterns that power production agent systems today.

Sequential Pipeline

Overview

  • Shape: A -> B -> C -> D
  • Keyword: "then"
  • Example: "Build, test, then deploy"
  • Risk: Long chains can be fragile
  • Max Steps: 7
  • SKILL.md Marker: Numbered steps with dependencies
  • Failure Mode: If step N fails, subsequent steps are skipped
  • Recovery: Fix step N, re-run from step N (if idempotent) or from step 1

Template

# Minimal Sequential Pipeline Template
## Steps
1. [First action] -> produces [output A]
2. [Second action using output A] -> produces [output B]
3. [Third action using output B] -> produces [final result]
## On Failure: Stop at failed step. Report step number and error.

Branching Router

Overview

  • Shape: Input -> {A | B | C}
  • Keyword: "if" / "depending on"
  • Example: "If guide, do X; if app, do Y"
  • Risk: Missing default handler
  • Max Branches: 5
  • SKILL.md Marker: IF/ELSE blocks or a routing table
  • Failure Mode: Input matches no route, leading to improvisation
  • Recovery: Add a DEFAULT route to show available options

Template

# Minimal Router Template
## Routing Logic
Parse input for: [type] and [action]
IF type = "A": -> [describe handler A]
IF type = "B": -> [describe handler B]
DEFAULT: -> Show available types and actions

Fan-Out Aggregator

Overview

  • Shape: Input -> [A, B, C] -> Merge
  • Keyword: "simultaneously" / "in parallel"
  • Example: "Run security, perf, and quality checks at once"
  • Risk: Aggregation complexity
  • Max Parallel: 4-5
  • SKILL.md Marker: "run in parallel" with an aggregation section
  • Failure Mode: One agent fails, resulting in partial aggregation
  • Recovery: Re-run the failed agent, merge with existing results

Template

# Minimal Fan-Out Template
## Fan-Out Phase (run in parallel)
Agent 1: [task] -> output format: [schema]
Agent 2: [task] -> output format: [schema]
Agent 3: [task] -> output format: [schema]
## Aggregation Phase
1. Collect all outputs
2. Merge using [strategy: concat | structured | prioritized]
3. Generate combined report

Stateful Loop

Overview

  • Shape: Do -> Check -> Repeat
  • Keyword: "until" / "keep trying"
  • Example: "Fix tests until they pass"
  • Risk: Infinite loops
  • Max Iterations: 5-10
  • SKILL.md Marker: WHILE block with state variables and exit conditions
  • Failure Mode: Agent loops indefinitely or repeats the same failing fix
  • Recovery: Implement a hard cap, progress detection, and scope limits

Template

# Minimal Loop Template
## State
- attempt: 0, max_attempts: 5, results: []
## Loop
WHILE [condition] AND attempt < max_attempts:
  1. [Action]
  2. [Evaluate result]
  3. [Update state]
  4. IF [success condition]: EXIT
  5. IF [stuck condition]: EXIT with report

Delegation Chain

Overview

  • Shape: Manager -> [Specialist A, Specialist B] -> Manager
  • Keyword: "delegate" / "hand off"
  • Example: "Architect designs, developers build, QA tests"
  • Risk: Context loss between agents
  • Max Depth: 2 levels
  • SKILL.md Marker: "Delegate to [Agent]" with input/output contracts
  • Failure Mode: Misunderstanding of tasks by child agents, leading to incorrect output
  • Recovery: Define more specific handoff contracts and include evaluation steps after each delegation

Template

# Minimal Delegation Template
## Delegation Flow
1. Delegate to [Agent A]:
   - Input: [what to pass]
   - Task: [what to do]
   - Output: [what to return]
2. Evaluate [Agent A] output: [criteria]
3. Delegate to [Agent B]:
   - Input: [output from Agent A]
   - Task: [what to do]
   - Output: [what to return]

Conclusion

These patterns are the backbone of successful agent systems. By understanding and applying them, you'll be equipped to build robust, efficient workflows that minimize downtime and maximize productivity. Remember, the key to mastery is practice and adaptation to your specific use cases. Keep this cheat sheet handy as you develop and refine your systems, and you'll find yourself debugging less and building more.