Skip to main content

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.

Teams adopting Hermes/OpenClaw bring skills as directories and need a migration map into PraisonAI’s discovery roots and activation UX.

Quick Start

1

Simple Import

Import an existing Hermes/OpenClaw skill into your PraisonAI project:
from praisonaiagents import Agent
from praisonaiagents.skills import discover_skills

# Discover skills from custom directory
skills = discover_skills(["/path/to/hermes-skills"])

agent = Agent(
    name="SkillAgent",
    instructions="Use imported skills to help users",
    skills=skills
)

agent.start("Process this data using available skills")
2

With Validation

Validate and safely import skills with error handling:
from praisonaiagents import Agent
from praisonaiagents.skills import validate, load_skill

# Validate skill before import
skill_path = "/path/to/hermes-skills/data-processor"
errors = validate(skill_path)

if not errors:
    skill = load_skill("data-processor", ["/path/to/hermes-skills"])
    agent = Agent(
        name="ValidatedAgent",
        instructions="Use validated skills only",
        skills=[skill] if skill else []
    )
else:
    print(f"Skill validation failed: {errors}")

How It Works

PhaseProcessOutput
DiscoveryScan directories for SKILL.md filesFound skills list
ValidationCheck format, dependencies, securityValidation report
IntegrationLoad into PraisonAI discovery rootsActive skills

Migration Dimensions

Artifact Inventory

Hermes/OpenClaw skills typically follow this structure:
skill-folder/
├── SKILL.md            ← frontmatter + body
├── scripts/            ← executable helpers (risk: platform-specific)  
└── references/         ← supplementary docs/data
PraisonAI handles these through its skill discovery system:

Configuration Options

OptionTypeDefaultDescription
skill_dirsList[str]NoneDirectories to scan for skills
include_defaultsboolTrueInclude built-in skill directories
validate_scriptsboolTrueValidate script security before execution
namespace_conflictsboolFalseAuto-namespace conflicting skill names

Step-by-Step Migration

1

Validate UTF-8 Encoding

Ensure all skill files use proper encoding (especially on Windows):
from pathlib import Path

def validate_encoding(skill_path: str) -> bool:
    """Validate all files in skill directory are UTF-8 encoded."""
    skill_dir = Path(skill_path)
    
    for file_path in skill_dir.rglob("*.md"):
        try:
            file_path.read_text(encoding='utf-8')
        except UnicodeDecodeError:
            print(f"Invalid encoding in {file_path}")
            return False
    
    return True
2

Lint Frontmatter

Check SKILL.md frontmatter against supported keys:
import yaml
from pathlib import Path

def lint_frontmatter(skill_path: str) -> list:
    """Lint SKILL.md frontmatter for compatibility."""
    skill_md = Path(skill_path) / "SKILL.md"
    content = skill_md.read_text()
    
    if not content.startswith('---'):
        return ["Missing YAML frontmatter"]
    
    # Extract frontmatter
    parts = content.split('---', 2)
    if len(parts) < 3:
        return ["Malformed frontmatter"]
    
    try:
        frontmatter = yaml.safe_load(parts[1])
        required_keys = ['name', 'description']
        missing = [key for key in required_keys if key not in frontmatter]
        return [f"Missing required key: {key}" for key in missing]
    except yaml.YAMLError as e:
        return [f"Invalid YAML: {e}"]
3

Place in Discovery Root

Copy to appropriate discovery directory:
import shutil
from pathlib import Path

def import_skill(source_path: str, target_dir: str = None) -> str:
    """Import Hermes/OpenClaw skill to PraisonAI discovery root."""
    source = Path(source_path)
    
    # Default to project-level skills directory
    if target_dir is None:
        target_dir = Path.cwd() / ".praisonai" / "skills"
    else:
        target_dir = Path(target_dir)
    
    target_dir.mkdir(parents=True, exist_ok=True)
    destination = target_dir / source.name
    
    # Handle name conflicts
    counter = 1
    while destination.exists():
        destination = target_dir / f"{source.name}-{counter}"
        counter += 1
    
    shutil.copytree(source, destination)
    return str(destination)
4

Test Discovery

Verify the skill is discoverable by PraisonAI:
from praisonaiagents.skills import discover_skills

def test_discovery(skills_dir: str) -> bool:
    """Test if imported skills are discoverable."""
    skills = discover_skills([skills_dir])
    
    if not skills:
        print("No skills discovered")
        return False
    
    for skill in skills:
        print(f"✓ Discovered: {skill.name} - {skill.description}")
    
    return True
5

Security Review

Strip secrets and validate script safety:
import re
from pathlib import Path

def security_review(skill_path: str) -> list:
    """Review skill for security issues."""
    issues = []
    skill_dir = Path(skill_path)
    
    # Check for hardcoded secrets
    secret_patterns = [
        r'api[_-]?key\s*=\s*["\'][^"\']+["\']',
        r'password\s*=\s*["\'][^"\']+["\']',
        r'token\s*=\s*["\'][^"\']+["\']'
    ]
    
    for file_path in skill_dir.rglob("*"):
        if file_path.is_file() and file_path.suffix in ['.md', '.py', '.txt']:
            content = file_path.read_text()
            for pattern in secret_patterns:
                if re.search(pattern, content, re.IGNORECASE):
                    issues.append(f"Potential secret in {file_path}")
    
    return issues

Runtime Bridges

Skills coexist with tools through layered integration:
  1. Skills provide instructions and safety policy text
  2. Tools provide mechanisms (API keys, quotas, auditing)
  3. MCP bridges host capabilities and external services

Tool Integration Pattern

from praisonaiagents import Agent
from praisonaiagents.tools import tool
from praisonaiagents.skills import load_skill

# Load Hermes skill
hermes_skill = load_skill("data-processor", ["/path/to/skills"])

# Create complementary tool
@tool
def process_data_api(data: str) -> str:
    """Process data using external API with proper auth."""
    # Tool handles API keys, rate limiting, etc.
    return api_call(data)

agent = Agent(
    name="HybridAgent", 
    skills=[hermes_skill],
    tools=[process_data_api]
)

Best Practices

Use consistent naming to avoid conflicts:
# Good: Namespaced skill names
"hermes/data-processor"
"openclaw/file-manager" 
"custom/my-skill"

# Bad: Generic names that conflict
"processor"
"manager"
"skill"
Review and sanitize script execution:
from praisonaiagents.skills import validate

# Always validate before importing
def safe_import(skill_path: str) -> bool:
    errors = validate(skill_path)
    if errors:
        print(f"Security issues: {errors}")
        return False
    
    # Additional security checks
    security_issues = security_review(skill_path)
    if security_issues:
        print(f"Security review failed: {security_issues}")
        return False
    
    return True
Track skill versions and compatibility:
# Include version in skill metadata
metadata = {
    "source": "hermes",
    "version": "1.2.0", 
    "compatibility": "praisonai>=0.1.0",
    "imported_at": "2024-01-15T10:30:00Z"
}
Test skills in isolation before deployment:
def test_imported_skill(skill_name: str) -> bool:
    """Test imported skill functionality."""
    skill = load_skill(skill_name)
    
    if not skill:
        return False
    
    # Create test agent
    test_agent = Agent(
        name="TestAgent",
        skills=[skill],
        instructions="Test the imported skill"
    )
    
    # Run test cases
    test_result = test_agent.start("Execute test scenario")
    return "error" not in test_result.lower()

Troubleshooting

Common Issues

ProblemSymptomsSolution
Skill not detectedEmpty discovery resultsCheck path, YAML format, UTF-8 encoding
Import errorsModule not foundVerify script dependencies, update requirements
Permission deniedScript execution failsReview file permissions, security settings
Name conflictsSkill override warningsUse namespacing or rename conflicting skills

Validation Checklist

  • SKILL.md exists and has valid YAML frontmatter
  • Required fields: name, description
  • UTF-8 encoding throughout
  • No hardcoded secrets in files
  • Scripts have proper dependencies
  • File permissions allow execution

Debug Commands

# Test skill discovery
praisonai skills list --dirs /path/to/hermes-skills

# Validate specific skill
praisonai skills validate --path /path/to/skill-folder

# Generate skills prompt XML
praisonai skills prompt --dirs /path/to/hermes-skills

Skills Overview

Learn about PraisonAI’s skill system architecture

Tool Integration

Understand tools vs skills differences