> ## Documentation Index
> Fetch the complete documentation index at: https://docs.praison.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Agent Skills

> Extend agent capabilities with modular skills following the open Agent Skills standard

# Agent Skills

Agent Skills is an open standard for extending AI agent capabilities with specialized knowledge and workflows. PraisonAI Agents fully supports the Agent Skills specification, enabling agents to load and use modular capabilities through SKILL.md files.

## Overview

Skills provide a way to give agents specialized knowledge and instructions without bloating the main system prompt. They use **progressive disclosure** to efficiently manage context:

1. **Level 1 - Metadata** (\~100 tokens): Name and description loaded at startup
2. **Level 2 - Instructions** (\<5000 tokens): Full SKILL.md body loaded when activated
3. **Level 3 - Resources** (as needed): Scripts, references, and assets loaded on demand

## Quick Start

### Using Skills with an Agent

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents import Agent

# Create an agent with specific skills
agent = Agent(
    name="PDF Assistant",
    instructions="You are a helpful assistant.",
    skills=["./skills/pdf-processing"],  # Direct skill paths
)

# Or discover skills from directories
agent = Agent(
    name="Multi-Skill Agent",
    instructions="You are a versatile assistant.",
    skills_dirs=["./skills"],  # Scan for skill subdirectories
)
```

### Using SkillManager Directly

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents import SkillManager

# Create a skill manager
manager = SkillManager()

# Discover skills from directories
manager.discover(["./skills"])

# Generate prompt XML for system prompt injection
prompt_xml = manager.to_prompt()
print(prompt_xml)
```

## SKILL.md Format

Each skill is a directory containing a `SKILL.md` file with YAML frontmatter:

```yaml theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
---
name: pdf-processing
description: Process and extract information from PDF documents. Use this skill when the user asks to read, analyze, or extract data from PDF files.
license: Apache-2.0
compatibility: Works with PraisonAI Agents
metadata:
  author: your-org
  version: "1.0"
allowed-tools: Read Write  # Optional: space-delimited tool list
---

# PDF Processing Skill

## Overview

This skill enables agents to process PDF documents...

## Instructions

1. First, verify the PDF file exists
2. Use appropriate tools to read the PDF content
3. Extract text while preserving structure
```

### Required Fields

| Field         | Description                            | Constraints                         |
| ------------- | -------------------------------------- | ----------------------------------- |
| `name`        | Skill identifier                       | 1-64 chars, lowercase, hyphens only |
| `description` | What the skill does and when to use it | 1-1024 chars                        |

### Optional Fields

| Field           | Description                                      |
| --------------- | ------------------------------------------------ |
| `license`       | License for the skill (e.g., Apache-2.0, MIT)    |
| `compatibility` | Compatibility information (max 500 chars)        |
| `metadata`      | Key-value pairs for custom properties            |
| `allowed-tools` | Space-delimited list of tools the skill requires |

## Directory Structure

```
my-skill/
├── SKILL.md          # Required: Skill definition
├── scripts/          # Optional: Executable code
├── references/       # Optional: Additional documentation
└── assets/           # Optional: Templates, data files
```

## Skill Discovery Locations

PraisonAI searches for skills in these locations (in order of precedence):

1. **Project**: `./.praison/skills/` or `./.claude/skills/`
2. **User**: `~/.praisonai/skills/`
3. **System**: `/etc/praison/skills/`

## CLI Commands

### List Available Skills

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai skills list
praisonai skills list --dirs ./my-skills ./other-skills
```

### Validate a Skill

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai skills validate --path ./my-skill
```

### Create a New Skill

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai skills create --name my-new-skill --description "A custom skill"
```

### Generate Prompt XML

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai skills prompt --dirs ./skills
```

## API Reference

### SkillManager

The main class for managing skills.

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents import SkillManager

manager = SkillManager()

# Discover skills
count = manager.discover(["./skills"], include_defaults=True)

# Add a single skill
skill = manager.add_skill("./path/to/skill")

# Get a skill by name
skill = manager.get_skill("pdf-processing")

# Activate a skill (load instructions)
manager.activate_by_name("pdf-processing")

# Get instructions
instructions = manager.get_instructions("pdf-processing")

# Generate prompt XML
prompt = manager.to_prompt()
```

### SkillLoader

For progressive loading of skills.

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents.skills import SkillLoader

loader = SkillLoader()

# Level 1: Load metadata only
skill = loader.load_metadata("./my-skill")

# Level 2: Activate (load instructions)
loader.activate(skill)
print(skill.instructions)

# Level 3: Load resources
scripts = loader.load_scripts(skill)
references = loader.load_references(skill)
assets = loader.load_assets(skill)
```

### Validation

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents.skills import validate, validate_metadata

# Validate a skill directory
errors = validate("./my-skill")
if errors:
    for error in errors:
        print(f"Error: {error}")
else:
    print("Skill is valid!")

# Validate metadata dict
errors = validate_metadata({"name": "test", "description": "Test skill"})
```

## Compatibility

PraisonAI's Agent Skills implementation follows the open standard, ensuring compatibility with:

* **Claude Code** (`.claude/skills/`)
* **GitHub Copilot** (`.github/skills/`)
* **Cursor** (Agent Skills support)
* **OpenAI Codex CLI**

PraisonAI supports both `.praison/skills/` and `.claude/skills/` for maximum compatibility.

## Performance

Agent Skills are designed for **zero performance impact** when not in use:

* **Lazy Loading**: Skills are only loaded when explicitly accessed
* **No Auto-discovery**: Discovery runs only when requested
* **Minimal Memory**: Skills not in use consume no memory
* **Progressive Disclosure**: Only load what's needed

## Direct API Integration Examples

### OpenAI API (gpt-4o-mini)

Complete flat file implementation showing how skills work with OpenAI's API:

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
"""
Agent Skills with OpenAI API using gpt-4o-mini.
Flat file code - no functions or classes.
"""

import os
from pathlib import Path
import yaml
from openai import OpenAI

# Initialize OpenAI client
client = OpenAI()

# Step 1: Discover skills from a directory
skill_dirs = ["./.praison/skills"]
skills = []

for dir_path in skill_dirs:
    dir_path = Path(dir_path).expanduser()
    if not dir_path.exists():
        continue
    
    for skill_path in dir_path.iterdir():
        if not skill_path.is_dir():
            continue
        
        skill_md = skill_path / "SKILL.md"
        if skill_md.exists():
            content = skill_md.read_text()
            
            # Extract frontmatter
            if content.startswith("---"):
                parts = content.split("---", 2)
                frontmatter = yaml.safe_load(parts[1])
                instructions = parts[2].strip()
                
                skills.append({
                    "name": frontmatter["name"],
                    "description": frontmatter["description"],
                    "instructions": instructions
                })

print(f"Discovered {len(skills)} skills")

# Step 2: Generate XML for system prompt
xml_parts = ["<available_skills>"]
for skill in skills:
    xml_parts.append(f"""  <skill>
    <name>{skill['name']}</name>
    <description>{skill['description']}</description>
  </skill>""")
xml_parts.append("</available_skills>")
skills_xml = "\n".join(xml_parts)

# Step 3: Create system prompt with skills
system_prompt = f"""You are a helpful AI assistant.

{skills_xml}

When a request matches a skill, respond with: "Using [skill-name] skill"
"""

# Step 4: Make API call with gpt-4o-mini
messages = [
    {"role": "system", "content": system_prompt},
    {"role": "user", "content": "Extract text from document.pdf"}
]

response = client.chat.completions.create(
    model="gpt-4o-mini",
    messages=messages
)

assistant_msg = response.choices[0].message.content
print(f"Assistant: {assistant_msg}")
messages.append({"role": "assistant", "content": assistant_msg})

# Step 5: If skill mentioned, activate it
activated = False
for skill in skills:
    if skill["name"] in assistant_msg.lower():
        print(f"Activating {skill['name']} skill")
        messages.append({
            "role": "user",
            "content": f"<skill_context>\n{skill['instructions']}\n</skill_context>"
        })
        activated = True
        break

# Step 6: Continue conversation with skill context
if activated:
    messages.append({"role": "user", "content": "Now help me with this task"})
    
    response = client.chat.completions.create(
        model="gpt-4o-mini",
        messages=messages
    )
    
    print(f"Assistant: {response.choices[0].message.content}")

# Show token usage
print(f"Total tokens: {response.usage.total_tokens}")
```

### Anthropic Claude API

Complete flat file implementation showing how skills work with Claude:

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
"""
Agent Skills with Anthropic Claude API.
Flat file code using Claude Sonnet 4.
"""

import os
from pathlib import Path
import yaml
from anthropic import Anthropic

# Initialize Anthropic client
client = Anthropic()

# Step 1: Discover skills from directory
skill_dirs = ["./.praison/skills"]
skills = []

for dir_path in skill_dirs:
    dir_path = Path(dir_path).expanduser()
    if not dir_path.exists():
        continue
    
    for skill_path in dir_path.iterdir():
        if not skill_path.is_dir():
            continue
        
        skill_md = skill_path / "SKILL.md"
        if skill_md.exists():
            content = skill_md.read_text()
            
            # Extract frontmatter
            if content.startswith("---"):
                parts = content.split("---", 2)
                frontmatter = yaml.safe_load(parts[1])
                instructions = parts[2].strip()
                
                skills.append({
                    "name": frontmatter["name"],
                    "description": frontmatter["description"],
                    "instructions": instructions
                })

print(f"Discovered {len(skills)} skills")

# Step 2: Generate XML for system prompt
xml_parts = ["<available_skills>"]
for skill in skills:
    xml_parts.append(f"""  <skill>
    <name>{skill['name']}</name>
    <description>{skill['description']}</description>
  </skill>""")
xml_parts.append("</available_skills>")
skills_xml = "\n".join(xml_parts)

# Step 3: Create system prompt with skills
system_prompt = f"""You are a helpful AI assistant.

{skills_xml}

When a request matches a skill, respond with: "Using [skill-name] skill"
"""

# Step 4: Make API call with Claude
messages = [
    {"role": "user", "content": "Extract text from document.pdf"}
]

response = client.messages.create(
    model="claude-sonnet-4-20250514",
    max_tokens=1024,
    system=system_prompt,
    messages=messages
)

assistant_msg = response.content[0].text
print(f"Assistant: {assistant_msg}")
messages.append({"role": "assistant", "content": assistant_msg})

# Step 5: If skill mentioned, activate it
activated = False
for skill in skills:
    if skill["name"] in assistant_msg.lower():
        print(f"Activating {skill['name']} skill")
        messages.append({
            "role": "user",
            "content": f"<skill_context>\n{skill['instructions']}\n</skill_context>"
        })
        activated = True
        break

# Step 6: Continue conversation with skill context
if activated:
    messages.append({"role": "user", "content": "Now help me with this task"})
    
    response = client.messages.create(
        model="claude-sonnet-4-20250514",
        max_tokens=1024,
        system=system_prompt,
        messages=messages
    )
    
    print(f"Assistant: {response.content[0].text}")

# Show token usage
print(f"Total tokens: {response.usage.input_tokens + response.usage.output_tokens}")
```

### Key Differences Between OpenAI and Claude

| Aspect              | OpenAI                                | Claude                                        |
| ------------------- | ------------------------------------- | --------------------------------------------- |
| **System Prompt**   | Message with `role: "system"`         | Separate `system` parameter                   |
| **Response Access** | `response.choices[0].message.content` | `response.content[0].text`                    |
| **Token Usage**     | `response.usage.total_tokens`         | `response.usage.input_tokens + output_tokens` |
| **Max Tokens**      | Optional                              | Required parameter                            |

## Examples

See the [examples/skills/](https://github.com/MervinPraison/PraisonAI/tree/main/examples/skills) directory for complete examples:

* `basic_skill_usage.py` - Basic skill discovery and usage
* `custom_skill_example.py` - Creating custom skills programmatically
* `pdf-processing/` - Example skill directory

***

## Managing Skills at Runtime

Agents can now create, edit, and manage their own skills dynamically through the self-improving skills system. This enables agents to learn from interactions and build persistent knowledge.

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
from praisonaiagents import Agent

# Agent with skill management capabilities
agent = Agent(
    name="Learning Assistant",
    instructions="Learn from user interactions and create skills for future use.",
    tools=["skill_manage", "skills_list", "skill_view"]
)

# Agent can now call:
# skill_manage(action="create", name="user-preference", content="Remember user likes...")
# skill_manage(action="edit", name="user-preference", content="Updated preferences...")
# skills_list() - to see all available skills
# skill_view("user-preference") - to examine skill details
```

### Runtime Skill Operations

| Tool           | Purpose                               | When to Use                               |
| -------------- | ------------------------------------- | ----------------------------------------- |
| `skill_manage` | Create, edit, patch, or delete skills | When learning new patterns or procedures  |
| `skills_list`  | List all available skills             | To review existing capabilities           |
| `skill_view`   | View detailed skill content           | To understand specific skill instructions |

For complete details on runtime skill management, see the dedicated [Self-Improving Skills](/docs/features/skill-manage) documentation.

***

## Compliance Verification

### ✅ FULLY COMPLIANT with agentskills.io Specification

PraisonAI's Agent Skills implementation is fully compliant with the official [agentskills.io](https://agentskills.io) specification.

#### Core Requirements

| Requirement                     | Spec                                            | PraisonAI Implementation              | Status |
| ------------------------------- | ----------------------------------------------- | ------------------------------------- | ------ |
| **SKILL.md file**               | Required in skill directory                     | `find_skill_md()` in `parser.py`      | ✅      |
| **YAML frontmatter**            | Must start with `---`                           | `parse_frontmatter()` validates this  | ✅      |
| **`name` field**                | Required, max 64 chars, lowercase, hyphens only | `_validate_name()` enforces all rules | ✅      |
| **`description` field**         | Required, max 1024 chars                        | `_validate_description()` enforces    | ✅      |
| **`license` field**             | Optional                                        | Supported in `SkillProperties`        | ✅      |
| **`compatibility` field**       | Optional, max 500 chars                         | `_validate_compatibility()` enforces  | ✅      |
| **`metadata` field**            | Optional key-value map                          | Supported in `SkillProperties`        | ✅      |
| **`allowed-tools` field**       | Optional, experimental                          | Supported as `allowed_tools`          | ✅      |
| **Directory name match**        | Must match `name` field                         | `_validate_name()` checks this        | ✅      |
| **No consecutive hyphens**      | `--` not allowed                                | Validated in `_validate_name()`       | ✅      |
| **No leading/trailing hyphens** | Cannot start/end with `-`                       | Validated in `_validate_name()`       | ✅      |

### ✅ Progressive Disclosure (3-Level Loading)

| Level                     | Spec                       | PraisonAI Implementation                               | Status |
| ------------------------- | -------------------------- | ------------------------------------------------------ | ------ |
| **Level 1: Metadata**     | \~100 tokens at startup    | `SkillMetadata` with name, description, location       | ✅      |
| **Level 2: Instructions** | \<5k tokens when triggered | `SkillLoader.activate()` loads SKILL.md body           | ✅      |
| **Level 3: Resources**    | As needed                  | `load_scripts()`, `load_references()`, `load_assets()` | ✅      |

### ✅ XML Prompt Generation

The spec requires this format for Claude models:

```xml theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
<available_skills>
  <skill>
    <name>pdf-processing</name>
    <description>...</description>
    <location>/path/to/SKILL.md</location>
  </skill>
</available_skills>
```

PraisonAI generates exactly this format in `prompt.py`:

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
def format_skill_for_prompt(skill: SkillMetadata) -> str:
    return f"""  <skill>
    <name>{name}</name>
    <description>{description}</description>
    <location>{location}</location>
  </skill>"""
```

### ✅ Skill Discovery

| Feature                | Spec                                        | PraisonAI                     | Status |
| ---------------------- | ------------------------------------------- | ----------------------------- | ------ |
| **Project-level**      | `./.praison/skills/` or `./.claude/skills/` | Both supported                | ✅      |
| **User-level**         | `~/.praisonai/skills/`                      | Supported                     | ✅      |
| **System-level**       | `/etc/praison/skills/`                      | Supported                     | ✅      |
| **Custom directories** | User-specified                              | `discover_skills(skill_dirs)` | ✅      |

### ✅ Directory Structure Support

```
skill-name/
├── SKILL.md           # Required ✅
├── scripts/           # Optional ✅
├── references/        # Optional ✅
└── assets/            # Optional ✅
```

### ✅ Agent Integration

* `Agent` class accepts `skills` and `skills_dirs` parameters
* Lazy loading via `skill_manager` property (zero performance impact)
* `get_skills_prompt()` returns XML for system prompt injection

### ✅ CLI Commands

| Command                            | Purpose                    | Status |
| ---------------------------------- | -------------------------- | ------ |
| `praisonai skills list`            | List available skills      | ✅      |
| `praisonai skills validate --path` | Validate skill directory   | ✅      |
| `praisonai skills create --name`   | Create skill from template | ✅      |
| `praisonai skills prompt`          | Generate XML prompt        | ✅      |

### ✅ Test Coverage

7 comprehensive test files covering all components:

* `test_parser.py` - Frontmatter parsing
* `test_validator.py` - All validation rules
* `test_discovery.py` - Skill discovery
* `test_loader.py` - Progressive loading
* `test_manager.py` - SkillManager
* `test_prompt.py` - XML generation
* `test_models.py` - Data models

### 🔍 Implementation Details

**Files Verified:**

**praisonaiagents/skills/**:

* `__init__.py` - Lazy loading exports
* `models.py` - `SkillProperties`, `SkillMetadata`
* `parser.py` - Frontmatter parsing
* `validator.py` - All validation rules per spec
* `discovery.py` - Directory scanning
* `loader.py` - Progressive disclosure (3 levels)
* `prompt.py` - XML generation
* `manager.py` - `SkillManager` class

**praisonai/cli/features/**:

* `skills.py` - CLI handler with list/validate/create/prompt commands

### Minor Observations (No Changes Required)

1. **Allowed fields validation**: PraisonAI rejects unexpected fields in frontmatter, which is stricter than the spec (spec allows arbitrary fields in `metadata`). This is actually **better** for catching errors.

2. **Case-insensitive SKILL.md**: PraisonAI accepts both `SKILL.md` and `skill.md`, which is more flexible than the spec.

3. **HTML escaping**: XML output properly escapes special characters via `html.escape()`.

### ✅ Conclusion

**PraisonAI's Agent Skills implementation is fully compliant with the agentskills.io specification.**

The implementation correctly follows:

* ✅ SKILL.md format with YAML frontmatter
* ✅ All field validation rules (name, description, compatibility limits)
* ✅ Progressive disclosure (3-level loading)
* ✅ XML prompt generation format
* ✅ Skill discovery from standard directories
* ✅ Zero performance impact when skills not used (lazy loading)
* ✅ CLI tools for skill management

**No changes are required.** The implementation aligns with the open Agent Skills standard as documented at [agentskills.io](https://agentskills.io).
