> ## 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.

# Skill Capability Gates

> Declare and enforce tool, server, and env requirements for Agent Skills

Skill Capability Gates allow you to declare tool, server, and environment variable requirements in your skills and enforce them at runtime with configurable strictness levels.

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph LR
    subgraph "Skill Capability Gates"
        A[📋 SKILL.md with requires_*] --> B[🔍 CapabilityValidator]
        B --> C{🛡️ Enforcement Level}
        C --> D[✅ ACTIVE]
        C --> E[⚠️ DEGRADED]  
        C --> F[❌ UNAVAILABLE]
    end
    
    classDef input fill:#6366F1,stroke:#7C90A0,color:#fff
    classDef process fill:#F59E0B,stroke:#7C90A0,color:#fff
    classDef success fill:#10B981,stroke:#7C90A0,color:#fff
    classDef warn fill:#F59E0B,stroke:#7C90A0,color:#fff
    classDef error fill:#DC2626,stroke:#7C90A0,color:#fff
    
    class A input
    class B,C process
    class D success
    class E warn
    class F error
```

## Quick Start

<Steps>
  <Step title="Simple Agent with Skill Requirements">
    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    from praisonaiagents import Agent

    agent = Agent(
        name="PDF Assistant",
        instructions="Process PDFs for the user",
        skills=["./skills/pdf-processor"]  # skill declares requires_tools
    )

    agent.start("Extract text from invoice.pdf")
    # → if requires_tools are missing, skill is degraded/unavailable based on enforcement level
    ```
  </Step>

  <Step title="Skill with Capability Requirements">
    Create a `SKILL.md` with requirements:

    ```yaml theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    ---
    name: pdf-processor
    description: Extract text and OCR from PDF documents
    requires_tools: [pdf_read, ocr_extract]
    requires_servers: ["mcp:filesystem"]
    requires_env: [OPENAI_API_KEY]
    ---

    # PDF Processing Instructions
    When asked to process a PDF, call pdf_read first, then ocr_extract for image pages.
    ```
  </Step>
</Steps>

***

## How It Works

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
sequenceDiagram
    participant Agent
    participant SkillManager
    participant Validator
    participant Registry
    
    Agent->>SkillManager: discover skills
    SkillManager->>Validator: validate_skill(properties)
    Validator->>Registry: check available tools/servers
    Registry-->>Validator: available capabilities
    Validator-->>SkillManager: ValidationResult
    SkillManager-->>Agent: filtered skills list
```

| Component               | Purpose                                         |
| ----------------------- | ----------------------------------------------- |
| **SkillRequirements**   | Parsed requirements from frontmatter            |
| **CapabilityValidator** | Validates skills against available capabilities |
| **ValidationResult**    | Per-skill validation status and details         |
| **EnforcementLevel**    | Controls strictness of requirement checking     |

***

## Frontmatter Reference

All frontmatter keys are **optional** and **backward-compatible**. Existing skills without requirements are unaffected.

| Frontmatter Key    | Aliases            | Type                  | Maps to                                          |
| ------------------ | ------------------ | --------------------- | ------------------------------------------------ |
| `requires_tools`   | `requires-tools`   | `list[str]` or string | `SkillRequirements.tools`                        |
| `requires_servers` | `requires-servers` | `list[str]` or string | `SkillRequirements.servers`                      |
| `requires_env`     | `requires-env`     | `list[str]` or string | `SkillRequirements.env_vars`                     |
| `allowed-tools`    | —                  | `list[str]` or string | **Also** appended to `tools` (backward compat)   |
| `openclaw`         | —                  | `dict`                | `SkillRequirements.openclaw_hints` (passthrough) |

**String forms are normalized** — both `requires_tools: "pdf_read, ocr_extract"` and `requires_tools: "pdf_read ocr_extract"` work.

***

## Skill States

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph TB
    A[Skill Validation] --> B{Has Requirements?}
    B -->|No| C[ACTIVE]
    B -->|Yes| D{All Satisfied?}
    D -->|Yes| C
    D -->|No| E{Critical Missing?}
    E -->|No| F[DEGRADED]
    E -->|Yes| G[UNAVAILABLE]
    
    classDef active fill:#10B981,stroke:#7C90A0,color:#fff
    classDef degraded fill:#F59E0B,stroke:#7C90A0,color:#fff
    classDef unavailable fill:#DC2626,stroke:#7C90A0,color:#fff
    
    class C active
    class F degraded
    class G unavailable
```

| State           | Meaning                                       | Behavior                                |
| --------------- | --------------------------------------------- | --------------------------------------- |
| **ACTIVE**      | All requirements satisfied                    | Skill fully available                   |
| **DEGRADED**    | Some requirements missing (env vars)          | Skill available with warnings           |
| **UNAVAILABLE** | Critical requirements missing (tools/servers) | Under strict mode, excluded from picker |
| **UNKNOWN**     | Not yet validated                             | Initial state before validation         |

***

## Enforcement Levels

```mermaid theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
graph TB
    A[Choose Enforcement Level] --> B{Environment?}
    B -->|Exploring/Development| C[DISABLED]
    B -->|Production with Telemetry| D[TELEMETRY]
    B -->|Development with Warnings| E[WARN - Default]
    B -->|Production Hard-Gate| F[STRICT]
    
    classDef disabled fill:#6B7280,stroke:#7C90A0,color:#fff
    classDef telemetry fill:#189AB4,stroke:#7C90A0,color:#fff
    classDef warn fill:#F59E0B,stroke:#7C90A0,color:#fff
    classDef strict fill:#DC2626,stroke:#7C90A0,color:#fff
    
    class C disabled
    class D telemetry
    class E warn
    class F strict
```

| Level         | Value         | Behavior                                                            | Logging    |
| ------------- | ------------- | ------------------------------------------------------------------- | ---------- |
| **DISABLED**  | `"disabled"`  | No enforcement (legacy behavior)                                    | None       |
| **TELEMETRY** | `"telemetry"` | Log-only, no blocking                                               | Debug/warn |
| **WARN**      | `"warn"`      | **Default** — surface warnings, allow activation                    | Warning    |
| **STRICT**    | `"strict"`    | Hard fail — skills in UNAVAILABLE state excluded from system prompt | Error      |

***

## Configuration

### Environment Variable

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# Set enforcement level (case-insensitive)
export SKILL_CAPABILITY_ENFORCEMENT=strict

# Accepted values
SKILL_CAPABILITY_ENFORCEMENT=disabled  # or 'off'
SKILL_CAPABILITY_ENFORCEMENT=telemetry # or 'log'
SKILL_CAPABILITY_ENFORCEMENT=warn      # or 'warning' (default)
SKILL_CAPABILITY_ENFORCEMENT=strict    # or 'hard', 'fail'
```

### Programmatic Configuration

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

# Default (uses environment or 'warn')
manager = SkillManager()

# Explicit enforcement level
manager = SkillManager(enforcement_level=EnforcementLevel.STRICT)
```

***

## Diagnostics from Code

### Basic Validation

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

manager = SkillManager()
manager.discover(["./skills"])

# Validate specific skill
result = manager.validate_skill_capabilities("pdf-processor")
print(f"State: {result.state.value}")
print(f"Missing tools: {result.missing_tools}")
print(f"Missing servers: {result.missing_servers}")
```

### Full Diagnostics

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# Get diagnostics for all skills
diagnostics = manager.get_skills_diagnostics()

for name, result in diagnostics.items():
    print(f"{name}: {result.state.value}")
    if result.warnings:
        print(f"  Warnings: {result.warnings}")
    if result.errors:
        print(f"  Errors: {result.errors}")
```

### Filter Skills by State

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

# Get only active skills
active_skills = manager.get_available_skills_by_state(SkillState.ACTIVE)

# Get degraded skills
degraded_skills = manager.get_available_skills_by_state(SkillState.DEGRADED)
```

***

## CLI Diagnostics

### Basic Skills Check

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai doctor skills                  # Basic skills health check
praisonai doctor skills --deep           # Deeper probes
praisonai doctor skills --json           # JSON output
```

### Detailed Requirements Check

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
praisonai doctor skills --requirements   # Show detailed per-skill diagnostics
```

**Sample output structure:**

```json theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
{
  "total_skills": 5,
  "active": 3,
  "degraded": 1,
  "unavailable": 1,
  "enforcement_level": "warn",
  "sample_issues": [
    "pdf-processor: Missing required tools: pdf_read",
    "email-sender: Missing required environment variables: SMTP_PASSWORD"
  ]
}
```

***

## Common Patterns

### Soft-warn in Dev, Strict in Prod

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
import os

# Production configuration
if os.getenv('ENV') == 'production':
    os.environ['SKILL_CAPABILITY_ENFORCEMENT'] = 'strict'
else:
    os.environ['SKILL_CAPABILITY_ENFORCEMENT'] = 'warn'

from praisonaiagents import Agent
agent = Agent(skills=["./skills"])
```

### Add Tool Requirement to Existing Skill

```yaml theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
---
name: existing-skill
description: Existing skill functionality
# Add new requirement
requires_tools: [new_required_tool]
---
```

### Filter to Active-Only Skills for System Prompt

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

# Strict mode automatically filters system prompt
manager = SkillManager(enforcement_level=EnforcementLevel.STRICT)
manager.discover()

# Only active skills included in prompt
prompt_xml = manager.to_prompt()
```

***

## Best Practices

<AccordionGroup>
  <Accordion title="Prefer requires_tools over allowed-tools for new skills">
    Use the new `requires_tools` frontmatter key for better validation:

    ```yaml theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    # Preferred (new)
    requires_tools: [pdf_read, ocr_extract]

    # Still supported (legacy)
    allowed-tools: [pdf_read, ocr_extract]
    ```
  </Accordion>

  <Accordion title="Use requires_env sparingly (prefer tool-level auth)">
    Minimize environment variable dependencies:

    ```yaml theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    # Prefer tool-level authentication
    requires_tools: [authenticated_api_client]

    # Avoid if possible
    requires_env: [API_KEY, SECRET_TOKEN]
    ```
  </Accordion>

  <Accordion title="Default to warn in development, strict in production">
    Configure appropriate enforcement levels:

    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    # Development
    SKILL_CAPABILITY_ENFORCEMENT=warn

    # Production
    SKILL_CAPABILITY_ENFORCEMENT=strict
    ```
  </Accordion>

  <Accordion title="Cache validation results (validator already caches; document clear_cache())">
    Validation results are automatically cached for performance:

    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    manager = SkillManager()

    # First call validates and caches
    result1 = manager.validate_skill_capabilities("skill-name")

    # Second call uses cache
    result2 = manager.validate_skill_capabilities("skill-name")

    # Force refresh
    result3 = manager.validate_skill_capabilities("skill-name", force_refresh=True)

    # Clear all caches
    manager.clear()
    ```
  </Accordion>
</AccordionGroup>

***

## Related

<CardGroup cols={2}>
  <Card title="Agent Skills" icon="puzzle-piece" href="/features/skills">
    Learn about the Agent Skills system and how to create skills
  </Card>

  <Card title="Hermes/OpenClaw Import" icon="download" href="/features/hermes-openclaw-skills-import">
    Import skills from Hermes and OpenClaw with capability requirements
  </Card>

  <Card title="Skill Management" icon="wrench" href="/features/skill-manage">
    Manage skills programmatically with the SkillManager API
  </Card>

  <Card title="Doctor CLI" icon="stethoscope" href="/cli/doctor">
    Use the doctor command to diagnose skill capability issues
  </Card>
</CardGroup>
