Agent Skills vs AGENTS.md: Designing Modular LLM Agent Behaviors

Explore two powerful approaches to building maintainable AI systems: code-based agent skills versus declarative AGENTS.md specifications. Learn when to use each pattern.

As large language models become increasingly integrated into production systems, the challenge of designing maintainable, scalable agent architectures has emerged as a critical concern. Two distinct approaches have gained traction: agent skills and the AGENTS.md specification. Understanding the tradeoffs between these paradigms is essential for building robust AI systems.


What Are Agent Skills?

Agent skills represent a modular, function-based approach to defining agent capabilities. Each skill encapsulates a specific behavior, tool, or capability that an agent can invoke. Think of skills as reusable building blocks that agents can dynamically compose to solve complex tasks.

Core Characteristics

Modularity: Each skill is self-contained with its own:

  • Input/output schema
  • Execution logic
  • Error handling
  • Documentation

Composability: Skills can be chained, nested, or conditionally executed based on context.

Runtime Discovery: Agents can discover and load skills dynamically, enabling flexible behavior adaptation.

Example Skill Definition

Python
class WebSearchSkill:
    name = "web_search"
    description = "Search the web for current information"
    
    def execute(self, query: str, max_results: int = 5):
        """Execute web search and return structured results"""
        return {
            "results": search_engine.query(query, limit=max_results),
            "timestamp": datetime.now(),
            "source": "bing_api"
        }

What Is AGENTS.md?

The AGENTS.md specification is an emerging standard for defining agent behaviors through declarative markdown documents. Instead of code, developers describe agent capabilities, instructions, and constraints in a human-readable format.

Key Principles

Declarative Configuration: Agent behavior is specified through structured markdown rather than imperative code.

Human-Readable: Non-technical stakeholders can understand and contribute to agent definitions.

Version-Controlled: Agent configurations live alongside code in version control systems.

Example AGENTS.md Structure

Markdown
# Customer Support Agent

## Purpose
Handle customer inquiries, resolve common issues, and escalate complex problems.

## Capabilities
- Query knowledge base
- Access order history
- Process refunds up to $100
- Escalate to human agent when needed

## Constraints
- Never promise refunds over $100
- Always verify customer identity
- Maintain professional tone

## Tools
- `search_kb(query: str)` - Search knowledge base
- `get_order(order_id: str)` - Retrieve order details
- `escalate(reason: str)` - Hand off to human agent

Why Modular Agent Design Matters

Modern LLM applications face several critical challenges that modular design addresses:

Maintainability at Scale

As agent systems grow, monolithic prompt engineering becomes unmanageable. Modular approaches allow teams to:

  • Isolate changes to specific capabilities
  • Test individual components independently
  • Reduce regression risks

Team Collaboration

In large organizations, multiple teams contribute to agent capabilities. Modular design enables:

  • Clear ownership boundaries
  • Parallel development
  • Specialized skill development

Performance Optimization

Different contexts require different capabilities. Modular systems can:

  • Load only required skills, reducing token usage
  • Implement capability-specific optimizations
  • Cache frequently-used modules

Architecture Comparison

| Aspect | Agent Skills | AGENTS.md | |--------|-------------|-----------|| | Definition Method | Code-based (Python, TypeScript) | Markdown specification | | Learning Curve | Steeper (requires programming) | Gentle (readable by non-devs) | | Flexibility | High (full programmatic control) | Medium (constrained by spec) | | Type Safety | Strong (with typed languages) | Weak (text-based) | | Version Control | Standard code versioning | Markdown diffing | | Execution Model | Direct function calls | Interpreted by agent runtime | | Testing | Unit tests, integration tests | Behavioral validation | | Debugging | Stack traces, breakpoints | Log analysis, prompt tracing |


Implementing Agent Skills

Let's build a practical example demonstrating the skills-based approach.

Step 1: Define Skill Interface

Python
from abc import ABC, abstractmethod
from typing import Dict, Any

class AgentSkill(ABC):
    @property
    @abstractmethod
    def name(self) -> str:
        pass
    
    @property
    @abstractmethod
    def description(self) -> str:
        pass
    
    @abstractmethod
    def execute(self, **kwargs) -> Dict[str, Any]:
        pass

Step 2: Create Concrete Skills

Python
class DataAnalysisSkill(AgentSkill):
    name = "analyze_data"
    description = "Perform statistical analysis on datasets"
    
    def execute(self, data: list, analysis_type: str):
        if analysis_type == "summary":
            return {
                "mean": sum(data) / len(data),
                "min": min(data),
                "max": max(data),
                "count": len(data)
            }
        elif analysis_type == "distribution":
            # Histogram logic here
            pass

Step 3: Build Skill Registry

Python
class SkillRegistry:
    def __init__(self):
        self._skills = {}
    
    def register(self, skill: AgentSkill):
        self._skills[skill.name] = skill
    
    def get_skill(self, name: str) -> AgentSkill:
        return self._skills.get(name)
    
    def list_skills(self) -> list:
        return [
            {"name": s.name, "description": s.description}
            for s in self._skills.values()
        ]

Step 4: Agent Execution Engine

Python
class SkillBasedAgent:
    def __init__(self, llm, registry: SkillRegistry):
        self.llm = llm
        self.registry = registry
    
    async def execute_task(self, task: str):
        # LLM decides which skills to use
        plan = await self.llm.generate(
            f"Available skills: {self.registry.list_skills()}\n"
            f"Task: {task}\n"
            f"Generate execution plan as JSON."
        )
        
        results = []
        for step in plan["steps"]:
            skill = self.registry.get_skill(step["skill_name"])
            result = skill.execute(**step["parameters"])
            results.append(result)
        
        return results

Implementing AGENTS.md Specification

Now let's explore implementing a runtime for AGENTS.md files.

Step 1: Define the Spec Schema

YAML
# agents.schema.yml
agent:
  required:
    - name
    - purpose
    - capabilities
  optional:
    - constraints
    - tools
    - examples
    - escalation_policy

Step 2: Parser Implementation

Python
import re
from dataclasses import dataclass

@dataclass
class AgentDefinition:
    name: str
    purpose: str
    capabilities: list[str]
    constraints: list[str]
    tools: dict[str, str]

class AgentMDParser:
    def parse(self, markdown_content: str) -> AgentDefinition:
        sections = self._split_sections(markdown_content)
        
        return AgentDefinition(
            name=self._extract_title(markdown_content),
            purpose=sections.get("Purpose", ""),
            capabilities=self._parse_list(sections.get("Capabilities", "")),
            constraints=self._parse_list(sections.get("Constraints", "")),
            tools=self._parse_tools(sections.get("Tools", ""))
        )
    
    def _split_sections(self, content: str) -> dict:
        sections = {}
        current_section = None
        
        for line in content.split("\n"):
            if line.startswith("## "):
                current_section = line[3:].strip()
                sections[current_section] = ""
            elif current_section:
                sections[current_section] += line + "\n"
        
        return sections

Step 3: Runtime Executor

Python
class AgentMDRuntime:
    def __init__(self, agent_def: AgentDefinition, tool_registry):
        self.definition = agent_def
        self.tools = tool_registry
    
    async def execute(self, user_input: str):
        # Build context from AGENTS.md
        context = f"""
        You are: {self.definition.name}
        Purpose: {self.definition.purpose}
        
        You can:
        {chr(10).join(f"- {cap}" for cap in self.definition.capabilities)}
        
        Constraints:
        {chr(10).join(f"- {con}" for con in self.definition.constraints)}
        
        Available tools: {list(self.definition.tools.keys())}
        """
        
        # Execute with LLM
        response = await llm.chat(
            system=context,
            user=user_input
        )
        
        return response

Best Practices for Modular Agent Design

For Agent Skills

✅ Keep skills atomic: Each skill should do one thing well

✅ Define clear interfaces: Use type hints and schema validation

✅ Implement robust error handling: Skills should fail gracefully

✅ Write comprehensive tests: Unit test each skill independently

✅ Document expected inputs/outputs: Include examples in docstrings

✅ Version your skills: Use semantic versioning for skill APIs

For AGENTS.md

✅ Be explicit about constraints: Don't rely on implicit behavior

✅ Maintain consistency: Use standard formatting across all agents

✅ Include examples: Show expected behaviors with sample interactions

✅ Keep it concise: Verbose specs lead to token waste

✅ Review regularly: Agent definitions should evolve with requirements

✅ Validate at deploy time: Catch spec errors before runtime


Common Mistakes to Avoid

❌ Over-engineering skills: Start simple, add complexity as needed

❌ Tight coupling: Skills shouldn't depend on each other's implementation

❌ Ignoring performance: Monitor token usage and latency per skill

❌ Incomplete error handling: Always account for tool failures

❌ Lack of observability: Instrument skills for debugging

❌ Static agent definitions: Build mechanisms for runtime adaptation

❌ Mixing paradigms inconsistently: Choose one primary approach


Real-World Use Cases

E-Commerce Support Agent (Skills-Based)

Python
skills = [
    OrderLookupSkill(),
    InventoryCheckSkill(),
    RefundProcessingSkill(),
    ShippingTrackingSkill(),
    ProductRecommendationSkill()
]

agent = SkillBasedAgent(llm, SkillRegistry(skills))

This approach works well when operations require complex business logic, database transactions, and integration with multiple backend systems.

Content Moderation Agent (AGENTS.md)

Markdown
# Content Moderator

## Purpose
Review user-generated content for policy violations

## Capabilities
- Detect harmful content
- Identify spam patterns
- Flag copyright violations
- Assess sentiment

## Constraints
- Never auto-delete content without review
- Flag borderline cases for human review
- Respect regional content policies

This specification approach excels when behavior is primarily rule-based and benefits from easy audibility by compliance teams.


Hybrid Approaches

Many production systems combine both paradigms:

AGENTS.md for High-Level Behavior: Define agent personality, constraints, and decision frameworks

Skills for Execution: Implement concrete capabilities as code-based skills

Markdown
# Customer Service Agent

## Behavior
- Friendly and helpful tone
- Escalate after 3 failed resolution attempts

## Available Skills
- `search_knowledge_base()`
- `create_ticket()`
- `process_refund()`

This hybrid model provides the readability of AGENTS.md with the power and type safety of programmatic skills.


Choosing the Right Approach

Use Agent Skills When:

  • You need strong type safety and testing
  • Your team is engineering-focused
  • Capabilities involve complex logic or integrations
  • Performance optimization is critical

Use AGENTS.md When:

  • Non-technical stakeholders must understand agent behavior
  • Behavior is primarily rule-based
  • Rapid iteration on agent personality is needed
  • Compliance and auditability are paramount

Use Hybrid When:

  • You have diverse stakeholder requirements
  • System complexity justifies multiple abstraction layers
  • You want the best of both worlds

Conclusion and Next Steps

Both agent skills and AGENTS.md specifications are valuable tools for building modular LLM agent systems. Skills provide maximum flexibility and power, while AGENTS.md offers unmatched readability and accessibility.

Start with these steps:

  1. Audit your current agent architecture for modularity opportunities
  2. Identify capabilities that would benefit from isolation
  3. Choose the approach that best fits your team and requirements
  4. Build a small proof-of-concept before full migration
  5. Establish testing and observability practices early

The future of AI agent development lies in composability. Whether through code-based skills, declarative specifications, or hybrid approaches, modular design patterns will be essential for building maintainable, scalable AI systems.

The key is not which approach you choose, but that you design for modularity from day one.

Keep reading

More on Agents