> ## Documentation Index
> Fetch the complete documentation index at: https://extended-openai-conversation.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Creating Skills

> Build custom skills to extend your AI assistant

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)

```yaml theme={null}
---
name: your_skill_name
description: Brief description of what this skill does and when to use it
---
```

<ParamField path="name" type="string" required>
  Skill identifier (max 64 characters). Should match the directory name.
</ParamField>

<ParamField path="description" type="string" required>
  Brief description (max 1024 characters) shown in the skills list. The AI uses this to decide when to activate the skill.
</ParamField>

#### 2. Markdown Body (Instructions)

The body contains detailed instructions and examples for the AI:

```markdown theme={null}
# 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

<Columns cols={2}>
  <div>
    ✅ **Good**

    ```markdown theme={null}
    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"
    ```
  </div>

  <div>
    ❌ **Bad**

    ```markdown theme={null}
    Use this skill to get crypto prices.
    Run the script to get information.
    ```
  </div>
</Columns>

### Provide Examples

Include 2-3 concrete examples:

```markdown theme={null}
## 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:

````markdown theme={null}
## 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.
````

<Note>
  The AI will automatically resolve relative paths to absolute paths when executing commands.
</Note>

## Example: Cryptocurrency Skill

Here's a complete example:

### SKILL.md

```markdown theme={null}
---
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

```python theme={null}
#!/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

<AccordionGroup>
  <Accordion title="1. Clear description">
    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"
  </Accordion>

  <Accordion title="2. Step-by-step instructions">
    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
  </Accordion>

  <Accordion title="3. Command syntax">
    Show exact command syntax:

    ✅ Good: `python3 scripts/tool.py --param value`

    ❌ Bad: "Run the tool with parameters"
  </Accordion>

  <Accordion title="4. Response format">
    Specify how to format responses:

    **Example Response Format:**

    Format the price as: "{Name} ({Symbol}): \${Price} USD"

    Example: "Bitcoin (BTC): \$45,234.56 USD"
  </Accordion>

  <Accordion title="5. Error handling">
    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
  </Accordion>
</AccordionGroup>

## Testing Your Skill

<Steps>
  <Step title="Test scripts independently">
    Run your scripts manually to ensure they work. Navigate to the skill directory and execute the script with test input.
  </Step>

  <Step title="Install the skill">
    Copy to skills directory and call the reload\_skills service to register it.
  </Step>

  <Step title="Enable in Options">
    Go to Voice Assistants > Options and enable your skill from the list.
  </Step>

  <Step title="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.
  </Step>
</Steps>

**Testing Commands:**

Test your script:

```bash theme={null}
cd /config/extended_openai_conversation/skills/your_skill
python3 scripts/tool.py test_input
```

Reload skills:

```yaml theme={null}
service: extended_openai_conversation.reload_skills
```

## Common Patterns

### Pattern 1: Simple Script

```markdown theme={null}
---
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

```markdown theme={null}
---
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

```markdown theme={null}
---
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:

<Steps>
  <Step title="Create your skill">
    Follow the structure and best practices above
  </Step>

  <Step title="Test thoroughly">
    Test with various user queries and edge cases
  </Step>

  <Step title="Document clearly">
    Include clear description and usage examples
  </Step>

  <Step title="Submit pull request">
    Submit to `examples/skills/` in the [repository](https://github.com/jekalmin/extended_openai_conversation)
  </Step>
</Steps>

## Debugging

Enable debug logging:

```yaml theme={null}
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

<Warning>
  **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
</Warning>

## Next Steps

<CardGroup cols={2}>
  <Card title="Skills Overview" icon="list" href="/skills/overview">
    Back to skills overview
  </Card>

  <Card title="Functions" icon="code" href="/functions/overview">
    Skills work with functions
  </Card>

  <Card title="Examples" icon="lightbulb" href="/examples/skills">
    Browse skill examples
  </Card>

  <Card title="GitHub Repository" icon="github" href="https://github.com/jekalmin/extended_openai_conversation">
    View source code
  </Card>
</CardGroup>
