Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/nearai/ironclaw/llms.txt

Use this file to discover all available pages before exploring further.

Overview

Skills are SKILL.md files (YAML frontmatter + markdown prompt) that extend the agent’s behavior through prompt-level instructions. Unlike code-level tools (WASM/MCP), skills operate in the LLM context and are subject to trust-based authority attenuation.

Trust Model

Skills have two trust states that determine their authority:
  • Trusted: User-placed skills (local/workspace) with full tool access
  • Installed: Registry/external skills, restricted to read-only tools
The effective tool ceiling is determined by the lowest-trust active skill, preventing privilege escalation through skill mixing.

Trust Assignment

Skill trust is determined by location:
┌─────────────────────────────────────┬─────────┐
│ Location                            │ Trust   │
├─────────────────────────────────────┼─────────┤
│ <workspace>/skills/                 │ Trusted │
│ ~/.ironclaw/skills/                 │ Trusted │
│ ~/.ironclaw/installed_skills/       │ Installed│
│ Bundled with application            │ Trusted │
└─────────────────────────────────────┴─────────┘

SKILL.md Format

Structure

---
name: writing-assistant
version: "1.0.0"
description: Professional writing and editing
activation:
  keywords: ["write", "edit", "proofread"]
  patterns: ["(?i)\\b(write|draft)\\b.*\\b(email|letter)\\b"]
  tags: ["writing", "editing"]
  max_context_tokens: 2000
metadata:
  openclaw:
    requires:
      bins: ["vale"]       # Required binaries
      env: ["VALE_CONFIG"]  # Required env vars
      config: ["/etc/vale.ini"]  # Required files
---

# Skill Prompt

You are a professional writing assistant. Help the user with:

- Writing and editing professional documents
- Grammar and style improvements
- Tone and clarity adjustments

Use the `vale` tool for automated style checking when available.

Frontmatter Fields

Required

  • name: Alphanumeric, hyphens, underscores, dots. Max 64 chars. Pattern: ^[a-zA-Z0-9][a-zA-Z0-9._-]{0,63}$

Optional

  • version: Semantic version (default: "0.0.0")
  • description: Short summary
  • activation: When to activate this skill
  • metadata: OpenClaw-specific metadata (gating requirements)

Activation Criteria

activation:
  keywords: ["write", "edit"]  # Max 20, min 3 chars each
  patterns: ["(?i)write.*email"]  # Max 5 regex patterns
  tags: ["writing", "email"]  # Max 10, min 3 chars each
  max_context_tokens: 2000  # Token budget
Limits (enforced at load time):
  • Keywords: Max 20, min length 3 chars
  • Patterns: Max 5 regex patterns
  • Tags: Max 10, min length 3 chars
  • Token budget: Max 2x declared max_context_tokens

Gating Requirements

Skills can declare dependencies:
metadata:
  openclaw:
    requires:
      bins: ["vale", "aspell"]  # Must be on PATH
      env: ["VALE_CONFIG"]      # Must be set
      config: ["/etc/vale.ini"]  # Must exist
Skills failing gating checks are skipped during discovery.

Discovery and Loading

Directory Layouts

Two layouts are supported:

Flat Layout

skills/
  SKILL.md

Subdirectory Layout

skills/
  writing-assistant/
    SKILL.md
  code-review/
    SKILL.md

Discovery Order

Earlier locations win on name collision:
  1. Workspace skills (<workspace>/skills/) - Trusted
  2. User skills (~/.ironclaw/skills/) - Trusted
  3. Installed skills (~/.ironclaw/installed_skills/) - Installed

Load-Time Validation

  1. File size: Max 64 KiB
  2. Name validation: Matches ^[a-zA-Z0-9][a-zA-Z0-9._-]{0,63}$
  3. Frontmatter parsing: Valid YAML
  4. Activation limits: Keywords/patterns/tags within caps
  5. Token budget: Prompt size < 2x declared max_context_tokens
  6. Gating checks: Required bins/env/config present
  7. Symlink rejection: No symlinks allowed
  8. Line ending normalization: CRLF → LF

Loading Pipeline

// Load and validate skill
let raw_bytes = tokio::fs::read(path).await?;
let raw_content = String::from_utf8(raw_bytes)?;
let normalized = normalize_line_endings(&raw_content);
let parsed = parse_skill_md(&normalized)?;

// Check gating
let result = check_requirements(&parsed.manifest.metadata).await;
if !result.passed {
    return Err(GatingFailed);
}

// Compute hash
let content_hash = compute_hash(&parsed.prompt_content);

// Compile patterns
let compiled_patterns = LoadedSkill::compile_patterns(
    &parsed.manifest.activation.patterns
);

// Build loaded skill
LoadedSkill {
    manifest: parsed.manifest,
    prompt_content: parsed.prompt_content,
    trust,
    source,
    content_hash,
    compiled_patterns,
    lowercased_keywords,
    lowercased_tags,
}

Activation and Selection

Scoring Algorithm

pub fn score_skill(skill: &LoadedSkill, message: &str) -> f64 {
    let msg_lower = message.to_lowercase();
    let mut score = 0.0;
    
    // Exact keyword matches (weight: 10.0)
    for keyword in &skill.lowercased_keywords {
        if msg_lower == keyword {
            score += 10.0;
        } else if msg_lower.contains(keyword) {
            score += 5.0;  // Substring match
        }
    }
    
    // Regex pattern matches (weight: 15.0)
    for pattern in &skill.compiled_patterns {
        if pattern.is_match(message) {
            score += 15.0;
        }
    }
    
    // Tag matches (weight: 2.0)
    for tag in &skill.lowercased_tags {
        if msg_lower.contains(tag) {
            score += 2.0;
        }
    }
    
    score
}

Selection Process

  1. Score all skills against incoming message
  2. Filter skills with score > 0
  3. Sort by score (descending)
  4. Take top N skills (default: 3)
  5. Check total token budget
  6. Return selected skills

Tool Attenuation

When skills are active, tool access is restricted:
pub fn attenuate_tools(
    tools: &[Tool],
    lowest_trust: SkillTrust,
) -> Vec<Tool> {
    match lowest_trust {
        SkillTrust::Trusted => tools.to_vec(),  // Full access
        SkillTrust::Installed => {
            // Only read-only tools
            tools.iter()
                .filter(|t| is_read_only_tool(t.name()))
                .cloned()
                .collect()
        }
    }
}
Read-only tools:
  • Read
  • Glob
  • Grep
  • WebFetch
  • SkillCatalog
Write tools (blocked for Installed skills):
  • Write
  • Edit
  • Bash
  • Task
  • All other tools

Skill Injection

Skills are injected into the LLM context:
<skill name="writing-assistant" version="1.0.0" trust="trusted">
  You are a professional writing assistant. Help the user with:
  
  - Writing and editing professional documents
  - Grammar and style improvements
  - Tone and clarity adjustments
</skill>

<skill name="code-review" version="2.3.1" trust="installed">
  You are a code reviewer. Analyze code for:
  
  - Style and best practices
  - Potential bugs
  - Performance issues
</skill>

Security: Tag Breakout Prevention

Skill content is escaped to prevent tag injection:
pub fn escape_skill_content(content: &str) -> String {
    static SKILL_TAG_RE: LazyLock<Regex> = LazyLock::new(|| {
        Regex::new(r"(?i)</?[\s\x00]*skill").unwrap()
    });
    
    SKILL_TAG_RE.replace_all(content, |caps: &Captures| {
        let matched = caps.get(0).unwrap().as_str();
        format!("&lt;{}", &matched[1..])
    }).into_owned()
}
This prevents skills from:
  • Closing their own </skill> tag prematurely
  • Injecting fake <skill trust="trusted"> blocks
  • Breaking out via mixed case, whitespace, or null bytes

Managing Skills

Via CLI

# List loaded skills
ironclaw skill list

# Show skill details
ironclaw skill show writing-assistant

# Install from file
ironclaw skill install --file ~/Downloads/skill.md

# Install from ClawHub
ironclaw skill install writing-assistant

# Remove skill
ironclaw skill remove writing-assistant

# Reload all skills
ironclaw skill reload

Via Tool Call

The agent can manage skills:
<SkillInstall>
  <content>
  ---
  name: custom-skill
  description: My custom skill
  ---
  
  You are a helpful assistant.
  </content>
</SkillInstall>

<SkillRemove name="custom-skill" />

Programmatic API

use ironclaw::skills::SkillRegistry;

// Create registry
let mut registry = SkillRegistry::new(user_dir)
    .with_workspace_dir(workspace_dir)
    .with_installed_dir(installed_dir);

// Discover all skills
let loaded = registry.discover_all().await;
println!("Loaded {} skills", loaded.len());

// Install skill
let content = std::fs::read_to_string("skill.md")?;
registry.install_skill(&content).await?;

// Remove skill
registry.remove_skill("skill-name").await?;

// Find skill
if let Some(skill) = registry.find_by_name("writing-assistant") {
    println!("Found: {} v{}", skill.name(), skill.version());
}

Creating Skills

Simple Skill

---
name: my-skill
description: A simple skill
activation:
  keywords: ["help", "assist"]
---

You are a helpful assistant.

Advanced Skill

---
name: deployment-helper
version: "1.2.0"
description: Deployment planning and execution
activation:
  keywords: ["deploy", "release", "ship"]
  patterns:
    - "(?i)\\bdeploy\\b.*\\b(production|staging)\\b"
    - "(?i)\\brelease\\b.*\\bv?\\d+"
  tags: ["devops", "deployment"]
  max_context_tokens: 3000
metadata:
  openclaw:
    requires:
      bins: ["kubectl", "helm"]
      env: ["KUBECONFIG"]
---

# Deployment Helper

You are a DevOps expert specializing in Kubernetes deployments.

## Capabilities

- Plan deployment strategies
- Review manifests for issues
- Generate helm commands
- Troubleshoot deployment failures

## Guidelines

1. Always check `kubectl` version compatibility
2. Verify namespace before deploying
3. Use `--dry-run=client` for validation
4. Include rollback instructions

## Tools

Use `Bash` to run kubectl/helm commands when needed.

ClawHub Integration

Skills can be published to and installed from ClawHub:
# Search for skills
ironclaw skill search writing

# Install from ClawHub
ironclaw skill install writing-assistant

# Publish skill
ironclaw skill publish --file my-skill.md
Published skills are installed to ~/.ironclaw/installed_skills/ with Installed trust.

Best Practices

Skill Design

  1. Focused scope: One skill per domain (writing, code review, etc.)
  2. Clear activation: Use specific keywords and patterns
  3. Token budget: Keep prompts under 2000 tokens
  4. Gating: Declare binary/config dependencies
  5. Examples: Include example interactions in the prompt

Security

  1. Trust isolation: Don’t mix trusted and installed skills for sensitive tasks
  2. Review installed skills: Always review skill content before installing
  3. Workspace override: Place custom versions in workspace to override installed skills
  4. Symlink prohibition: Never use symlinks in skills directories

Performance

  1. Keyword limits: Use < 10 keywords per skill
  2. Pattern complexity: Avoid complex regex (max 64 KiB compiled size)
  3. Token budget: Larger prompts consume more context window
  4. Selective activation: Use precise patterns to avoid activating unnecessarily

Troubleshooting

Skill Not Loading

# Check logs
export RUST_LOG=ironclaw::skills=debug
ironclaw run

# Common issues:
# 1. Invalid YAML frontmatter
# 2. Name doesn't match pattern
# 3. File too large (> 64 KiB)
# 4. Failed gating checks
# 5. Symlink detected

Skill Not Activating

# Check activation criteria
ironclaw skill show my-skill

# Test scoring
export RUST_LOG=ironclaw::skills::selector=debug
ironclaw run

# Common issues:
# 1. Keywords too short (< 3 chars)
# 2. Pattern doesn't match message
# 3. Score too low (< threshold)

Tool Access Denied

Error: Tool 'Bash' not available (installed skill active)
Cause: Installed skill is active, restricting tools to read-only. Solution:
  1. Override the skill by placing a trusted version in workspace/user dir
  2. Remove the installed skill
  3. Use read-only tools only

Source Code

Key files:
  • src/skills/mod.rs - Module overview, types, escaping
  • src/skills/registry.rs - Discovery, loading, management
  • src/skills/parser.rs - SKILL.md parsing
  • src/skills/selector.rs - Activation scoring and selection
  • src/skills/attenuation.rs - Tool restriction based on trust
  • src/skills/gating.rs - Dependency checks (bins/env/config)
  • src/skills/catalog.rs - ClawHub integration

Build docs developers (and LLMs) love