Skip to main content
Create custom skills to add specialized capabilities to your AI assistant. This guide covers skill structure, best practices, and examples.

Skill Structure

Directory Layout

<config>/extended_openai_conversation/skills/
└── your_skill_name/
    ├── SKILL.md           # Required: skill definition
    ├── scripts/           # Optional: executable scripts
    │   └── tool.py
    └── reference/        # Optional: detailed reference material
        └── sales.md

SKILL.md Format

The SKILL.md file has two parts:

1. YAML Frontmatter (Required)

---
name: your_skill_name
description: Brief description of what this skill does and when to use it
---
name
string
required
Skill identifier (max 64 characters). Should match the directory name.
description
string
required
Brief description (max 1024 characters) shown in the skills list. The AI uses this to decide when to activate the skill.

2. Markdown Body (Instructions)

The body contains detailed instructions and examples for the AI:
# Skill Title

Detailed instructions for the AI on how to use this skill.

## Usage

Step-by-step guidance on what the AI should do.

## Examples

### Example 1
User: "example query"
Action: Specific steps the AI should take

## Notes

Any additional context or edge cases.

Writing Effective Instructions

Be Specific and Concrete

Good
When the user asks for cryptocurrency prices:

1. Call load_skill with name="crypto" and file="SKILL.md"
2. Run: `python3 scripts/crypto.py {symbol}`
3. Parse the JSON output
4. Format as: "{Symbol}: ${price} USD"
Bad
Use this skill to get crypto prices.
Run the script to get information.

Provide Examples

Include 2-3 concrete examples:
## Examples

### Example 1: Single cryptocurrency
User: "What's the Bitcoin price?"
1. Run: `python3 scripts/crypto.py BTC`
2. Response: "Bitcoin (BTC): $45,234.56 USD"

### Example 2: Multiple cryptocurrencies
User: "Show me ETH and SOL prices"
1. Run: `python3 scripts/crypto.py ETH SOL`
2. Format each result on a new line

Specify File Paths

Use relative paths in instructions:
## Running the Script

Execute the price lookup script:
```bash
python3 scripts/crypto.py {symbol}
```

The script is located at `scripts/crypto.py` relative to the skill directory.
The AI will automatically resolve relative paths to absolute paths when executing commands.

Example: Cryptocurrency Skill

Here’s a complete example:

SKILL.md

---
name: crypto
description: Get real-time cryptocurrency prices. Use when users ask about Bitcoin, Ethereum, or other crypto prices and market data.
---

# Cryptocurrency Price Checker

## Instructions

1. **Identify the cryptocurrency** the user is asking about (Bitcoin, Ethereum, Solana, etc.)

2. **Execute the appropriate script**
   - `python3 scripts/crypto.py btc` - Get Bitcoin price
   - `python3 scripts/crypto.py eth` - Get Ethereum price
   - `python3 scripts/crypto.py sol` - Get Solana price
   - `python3 scripts/crypto.py doge` - Get Dogecoin price
   - `python3 scripts/crypto.py <symbol>` - Get any crypto price by symbol

3. **Format the response** with:
   - USD price (and local currency if applicable)
   - 24-hour price change percentage
   - Source attribution to CoinGecko
   - Note that crypto prices are volatile and change rapidly

## Examples

**User:** "What's the current Bitcoin price?"
**Action:** Execute `python3 scripts/crypto.py btc`
**Response:** "Bitcoin is currently trading at $67,234. It has changed +2.3% in the last 24 hours. (Source: CoinGecko)"

**User:** "How much is Ethereum worth?"
**Action:** Execute `python3 scripts/crypto.py eth`
**Response:** "Ethereum is currently priced at $3,456, down -1.2% over the past 24 hours. (Source: CoinGecko)"

**User:** "Check Solana and Dogecoin prices"
**Action:** Execute `python3 scripts/crypto.py sol` and `python scripts/crypto.py doge`
**Response:** "Current prices - Solana: $145 (+5.7% 24h), Dogecoin: $0.12 (+0.8% 24h). (Source: CoinGecko)"

scripts/crypto.py

#!/usr/bin/env python3
"""Fetch cryptocurrency prices from CoinGecko API.

Usage: python crypto.py <symbol>
Example: python crypto.py btc
"""

from datetime import UTC, datetime
import json
import sys
import urllib.error
import urllib.request


def get_coin_id(symbol: str) -> str:
    """Map common symbols to CoinGecko IDs."""
    symbol_map = {
        "btc": "bitcoin",
        "bitcoin": "bitcoin",
        "eth": "ethereum",
        "ethereum": "ethereum",
        "sol": "solana",
        "solana": "solana",
        "xrp": "ripple",
        "ripple": "ripple",
        "ada": "cardano",
        "cardano": "cardano",
        "doge": "dogecoin",
        "dogecoin": "dogecoin",
    }
    return symbol_map.get(symbol.lower(), symbol.lower())


def fetch_crypto_price(coin_id: str) -> dict:
    """Fetch price from CoinGecko API."""
    url = f"https://api.coingecko.com/api/v3/simple/price?ids={coin_id}&vs_currencies=usd,krw&include_24hr_change=true"

    try:
        with urllib.request.urlopen(url) as response:
            data: dict = json.loads(response.read().decode())

        # Check if response contains error or empty data
        if not data or coin_id not in data:
            return {"error": f"Failed to fetch price for {coin_id}", "response": data}

        return data

    except urllib.error.URLError as e:
        return {
            "error": f"Network error while fetching price for {coin_id}",
            "details": str(e),
        }
    except json.JSONDecodeError as e:
        return {"error": f"Invalid JSON response for {coin_id}", "details": str(e)}


def main() -> None:
    """Main entry point."""
    # Get symbol from command line, default to 'btc'
    symbol = sys.argv[1] if len(sys.argv) > 1 else "btc"

    # Map symbol to CoinGecko ID
    coin_id = get_coin_id(symbol)

    # Fetch price data
    response = fetch_crypto_price(coin_id)

    # Check for errors in response
    if "error" in response:
        print(json.dumps(response))
        sys.exit(1)

    # Add timestamp and format final response
    timestamp = datetime.now(UTC).strftime("%Y-%m-%dT%H:%M:%SZ")
    result = {"coin": coin_id, "timestamp": timestamp, "data": response}

    print(json.dumps(result))


if __name__ == "__main__":
    main()

Best Practices

Write a concise description that helps the AI decide when to use the skill:✅ Good: “Get real-time cryptocurrency prices and market data. Use when users ask about crypto prices, market cap, or trading volume.”❌ Bad: “Crypto skill”
Provide numbered steps the AI can follow:Example:
  1. Load the skill file
  2. Extract the required parameters
  3. Run the script with parameters
  4. Parse the output
  5. Format the response
Show exact command syntax:✅ Good: python3 scripts/tool.py --param value❌ Bad: “Run the tool with parameters”
Specify how to format responses:Example Response Format:Format the price as: ” (): $ USD”Example: “Bitcoin (BTC): $45,234.56 USD”
Explain what to do when things go wrong:Error Handling Example:If script exits with error:
  • Check the error message in stderr
  • Verify input parameters
  • Inform user if service is unavailable

Testing Your Skill

1

Test scripts independently

Run your scripts manually to ensure they work. Navigate to the skill directory and execute the script with test input.
2

Install the skill

Copy to skills directory and call the reload_skills service to register it.
3

Enable in Options

Go to Voice Assistants > Options and enable your skill from the list.
4

Test with AI

Ask questions that should trigger the skill. Check logs to verify the skill is loaded, commands are executed, and output is parsed correctly.
Testing Commands: Test your script:
cd /config/extended_openai_conversation/skills/your_skill
python3 scripts/tool.py test_input
Reload skills:
service: extended_openai_conversation.reload_skills

Common Patterns

Pattern 1: Simple Script

---
name: simple_tool
description: Brief description of what this does
---

# Tool Name

## Usage
Run: `python3 scripts/tool.py {param}`

## Example
User: "Run the tool"
Action: `python3 scripts/tool.py value`

Pattern 2: API Integration

---
name: api_service
description: Fetch data from external API
---

# API Service

## Usage
1. Extract required parameters from user query
2. Run: `python3 scripts/api.py --param1 {value1} --param2 {value2}`
3. Parse JSON response
4. Format for user

## Examples
[Detailed examples here]

Pattern 3: Reference Data

---
name: knowledge_base
description: Answer questions using reference data
---

# Knowledge Base

## Usage
1. Load reference data: load_skill(name="knowledge_base", file="references/data.md")
2. Search for relevant information
3. Provide answer based on data

## Data Format
The reference data contains:
- field1: Description
- field2: Description

Contributing Skills

To share your skill with the community:
1

Create your skill

Follow the structure and best practices above
2

Test thoroughly

Test with various user queries and edge cases
3

Document clearly

Include clear description and usage examples
4

Submit pull request

Submit to examples/skills/ in the repository

Debugging

Enable debug logging:
logger:
  logs:
    custom_components.extended_openai_conversation: debug
Check logs for:
  • Skill loading and initialization
  • File reads (load_skill calls)
  • Script execution and output
  • Error messages

Security Considerations

Bash Execution Safety
  • Scripts run in the workspace directory (<config>/extended_openai_conversation/)
  • Destructive commands are blocked (rm -rf, etc.)
  • Scripts cannot access system directories
  • Review scripts before enabling bash function

Next Steps