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

# Recipe Author Persona

> Create and maintain PraisonAI recipes

# Recipe Author Persona

<Callout type="info">
  **Role**: Design, build, test, and document recipes that solve real-world problems for App Developers and end users.
</Callout>

## Primary Goals

* **Create effective recipes** that solve specific problems
* **Design clear interfaces** with well-defined inputs/outputs
* **Write comprehensive tests** for reliability
* **Document thoroughly** for easy adoption

## Recommended Knowledge

<CardGroup cols={2}>
  <Card title="All Integration Models" icon="diagram-project" href="/docs/guides/recipes/integration-models">
    Understand how recipes are consumed
  </Card>

  <Card title="Use Cases" icon="lightbulb" href="/docs/guides/recipes/use-cases">
    Learn from existing patterns
  </Card>

  <Card title="Decision Guide" icon="map" href="/docs/guides/recipes/decision-guide">
    Help users choose the right approach
  </Card>

  <Card title="App Developer Persona" icon="code" href="/docs/guides/recipes/personas/app-developer">
    Understand your users
  </Card>
</CardGroup>

## Typical Workflow

<Steps>
  <Step title="Define the Problem">
    ```yaml theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    # Start with a clear problem statement
    # What task does this recipe automate?
    # Who is the target user?
    # What are the expected inputs and outputs?

    # Example: Support Reply Drafter
    # Problem: Support agents spend too much time drafting replies
    # User: Support team members
    # Input: Ticket ID, customer message
    # Output: Draft reply text
    ```
  </Step>

  <Step title="Create Recipe Structure">
    ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    # Initialize recipe directory
    mkdir -p ~/.praisonai/templates/support-reply-drafter
    cd ~/.praisonai/templates/support-reply-drafter
    ```

    ```yaml theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    # TEMPLATE.yaml
    name: support-reply-drafter
    version: "1.0.0"
    description: "Generate professional support reply drafts"
    author: "Your Name"
    license: "MIT"

    tags:
      - support
      - customer-service
      - text-generation

    requires:
      env:
        - OPENAI_API_KEY
      packages:
        - praisonaiagents

    inputs:
      ticket_id:
        type: string
        description: "Support ticket identifier"
        required: true
      message:
        type: string
        description: "Customer message to respond to"
        required: true
      tone:
        type: string
        description: "Response tone"
        default: "professional"
        enum: ["professional", "friendly", "formal"]

    outputs:
      reply:
        type: string
        description: "Generated reply draft"
      confidence:
        type: number
        description: "Confidence score (0-1)"

    cli:
      command: "praisonai recipe run support-reply-drafter"
      examples:
        - 'praisonai recipe run support-reply-drafter --input ''{"ticket_id": "T-123", "message": "I need help"}'''

    safety:
      dry_run_default: false
      requires_consent: false
    ```
  </Step>

  <Step title="Implement the Recipe">
    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    # recipe.py
    from praisonaiagents import Agent, Task, AgentTeam

    def run(input_data: dict, config: dict = None) -> dict:
        """
        Generate a support reply draft.
        
        Args:
            input_data: Contains ticket_id, message, and optional tone
            config: Optional configuration overrides
            
        Returns:
            Dict with reply and confidence score
        """
        ticket_id = input_data.get("ticket_id")
        message = input_data.get("message")
        tone = input_data.get("tone", "professional")
        
        # Create support agent
        support_agent = Agent(
            name="Support Specialist",
            role="Customer Support Expert",
            goal=f"Draft a {tone} reply to customer inquiries",
            instructions="""
            You are an expert customer support specialist.
            - Be helpful and empathetic
            - Address the customer's concern directly
            - Provide clear next steps if applicable
            - Keep responses concise but complete
            """,
        )
        
        # Create task
        task = Task(
            name="draft_reply",
            description=f"""
            Draft a {tone} reply to this customer message:
            
            Ticket: {ticket_id}
            Message: {message}
            
            Provide a professional, helpful response.
            """,
            expected_output="A well-crafted support reply",
            agent=support_agent,
        )
        
        # Execute
        agents = AgentTeam(
            agents=[support_agent],
            tasks=[task],
        )
        
        result = agents.start()
        
        return {
            "reply": result.get("task_output", ""),
            "confidence": 0.85,  # Could be calculated from model response
        }
    ```
  </Step>

  <Step title="Write Tests">
    ```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    # test_recipe.py
    import pytest
    from recipe import run

    def test_basic_reply():
        """Test basic reply generation."""
        result = run({
            "ticket_id": "T-123",
            "message": "I can't log into my account",
        })
        
        assert "reply" in result
        assert len(result["reply"]) > 50
        assert result["confidence"] > 0.5

    def test_tone_professional():
        """Test professional tone."""
        result = run({
            "ticket_id": "T-124",
            "message": "Your product is broken!",
            "tone": "professional",
        })
        
        assert "reply" in result
        # Should not contain informal language
        assert "hey" not in result["reply"].lower()

    def test_tone_friendly():
        """Test friendly tone."""
        result = run({
            "ticket_id": "T-125",
            "message": "How do I reset my password?",
            "tone": "friendly",
        })
        
        assert "reply" in result

    def test_missing_required_field():
        """Test error handling for missing fields."""
        with pytest.raises(ValueError):
            run({"ticket_id": "T-126"})  # Missing message

    @pytest.mark.integration
    def test_end_to_end():
        """Full integration test."""
        from praisonai import recipe
        
        result = recipe.run(
            "support-reply-drafter",
            input={
                "ticket_id": "T-127",
                "message": "I need a refund",
            }
        )
        
        assert result.ok
        assert result.output.get("reply")
    ```
  </Step>

  <Step title="Document the Recipe">
    Create a README.md with:

    * **Title and description** - What the recipe does
    * **Quick start** - Minimal example to get started
    * **Inputs table** - All parameters with types and descriptions
    * **Outputs table** - What the recipe returns
    * **Examples** - Multiple usage scenarios
    * **Requirements** - Dependencies and environment variables
    * **Troubleshooting** - Common issues and solutions

    Example README structure:

    ```text theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
    # Recipe Name

    Description of what the recipe does.

    ## Quick Start
    praisonai recipe run my-recipe --input '{"key": "value"}'

    ## Inputs
    | Field | Type | Required | Description |
    |-------|------|----------|-------------|
    | field1 | string | Yes | Description |

    ## Outputs
    | Field | Type | Description |
    |-------|------|-------------|
    | output1 | string | Description |

    ## Examples
    [Code examples for different use cases]

    ## Requirements
    - OPENAI_API_KEY environment variable
    - praisonaiagents package

    ## Troubleshooting
    Common issues and solutions
    ```
  </Step>
</Steps>

## Key Concerns

### Interface Design

```yaml theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# Good: Clear, typed inputs with defaults
inputs:
  query:
    type: string
    required: true
    description: "Search query"
  max_results:
    type: integer
    default: 10
    minimum: 1
    maximum: 100
    description: "Maximum results to return"

# Bad: Vague, untyped inputs
inputs:
  data:
    description: "Input data"
```

### Error Handling

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
def run(input_data: dict, config: dict = None) -> dict:
    """Recipe with proper error handling."""
    
    # Validate required inputs
    if not input_data.get("query"):
        raise ValueError("query is required")
    
    try:
        # Main logic
        result = process(input_data)
        return {"output": result, "ok": True}
        
    except RateLimitError:
        return {"error": "Rate limit exceeded, try again later", "ok": False}
    except InvalidInputError as e:
        return {"error": f"Invalid input: {e}", "ok": False}
    except Exception as e:
        # Log for debugging but don't expose internals
        logger.error(f"Recipe failed: {e}")
        return {"error": "An unexpected error occurred", "ok": False}
```

### Testing Strategy

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# Unit tests - fast, isolated
def test_input_validation():
    with pytest.raises(ValueError):
        run({})

# Integration tests - with real APIs
@pytest.mark.integration
def test_with_real_api():
    result = run({"query": "test"})
    assert result["ok"]

# Snapshot tests - for output consistency
def test_output_format(snapshot):
    result = run({"query": "hello"})
    assert result == snapshot
```

## Best Practices

### Recipe Naming

```
✅ Good names:
- support-reply-drafter
- code-review-assistant
- document-summarizer

❌ Bad names:
- my-recipe
- test123
- agent
```

### Version Management

```yaml theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# Use semantic versioning
version: "1.2.3"
# 1 = major (breaking changes)
# 2 = minor (new features)
# 3 = patch (bug fixes)
```

### Dependency Management

```yaml theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
requires:
  packages:
    - praisonaiagents>=0.5.0  # Specify minimum versions
  env:
    - OPENAI_API_KEY  # Required
  optional_env:
    - LANGCHAIN_API_KEY  # Optional enhancement
```

## Troubleshooting

<Accordion title="Recipe not discovered">
  Check recipe location:

  ```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
  # Recipes are discovered from:
  ls ~/.praisonai/templates/
  ls ~/.config/praison/templates/
  ls ./.praison/templates/
  ```
</Accordion>

<Accordion title="Tests failing in CI">
  * Ensure API keys are set in CI secrets
  * Use mocks for unit tests
  * Mark integration tests appropriately
</Accordion>

<Accordion title="Users report inconsistent outputs">
  * Add temperature control to prompts
  * Implement output validation
  * Add retry logic for edge cases
</Accordion>

## Handoff Checklist

Before releasing a recipe:

* [ ] TEMPLATE.yaml is complete and valid
* [ ] All inputs have descriptions and types
* [ ] All outputs are documented
* [ ] README.md with examples
* [ ] Unit tests pass
* [ ] Integration tests pass
* [ ] Tested with all integration models (SDK, CLI, HTTP)
* [ ] Error messages are user-friendly
* [ ] Dependencies are specified with versions
* [ ] License is specified

## Next Steps

* [Integration Models](/docs/guides/recipes/integration-models) - How recipes are consumed
* [Use Cases](/docs/guides/recipes/use-cases) - Inspiration for new recipes
* [App Developer Persona](/docs/guides/recipes/personas/app-developer) - Understand your users

***

## SDK & Recipe Author Reference (Copy/Paste for AI)

<Callout type="tip">
  This section is designed to be copied wholesale and given to an AI assistant. It contains everything needed to build a complete, valid PraisonAI recipe from scratch.
</Callout>

### 1. Recipe Discovery

Recipes are discovered from these directories in order of precedence (first match wins):

| Priority | Path                                              | Description           |
| -------- | ------------------------------------------------- | --------------------- |
| 1        | `~/.praisonai/templates/`                         | User-local recipes    |
| 2        | `~/.config/praison/templates/`                    | XDG config location   |
| 3        | `./.praison/templates/`                           | Project-local recipes |
| 4        | `/path/to/Agent-Recipes/agent_recipes/templates/` | Built-in recipes      |

**Source**: `praisonai/cli/features/recipes.py` → `RECIPE_PATHS`, `find_recipe_paths()`

### 2. Recipe Directory Structure

```
my-recipe/
├── TEMPLATE.yaml      # Required: Recipe metadata and configuration
├── README.md          # Required: Documentation
├── recipe.py          # Required: Main entrypoint with run() function
├── test_recipe.py     # Recommended: Tests
└── requirements.txt   # Optional: Additional dependencies
```

### 3. TEMPLATE.yaml Complete Schema

```yaml theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# ═══════════════════════════════════════════════════════════════════════════
# TEMPLATE.yaml - Complete Schema Reference
# ═══════════════════════════════════════════════════════════════════════════

# ─────────────────────────────────────────────────────────────────────────────
# METADATA (Required)
# ─────────────────────────────────────────────────────────────────────────────
name: my-recipe-name              # Required: Unique identifier (kebab-case)
version: "1.0.0"                  # Required: Semantic version string
description: "Short description"  # Required: One-line description
author: "Your Name"               # Required: Author name or handle
license: "MIT"                    # Required: SPDX license identifier

# ─────────────────────────────────────────────────────────────────────────────
# TAGS (Required)
# ─────────────────────────────────────────────────────────────────────────────
tags:                             # Required: At least one tag
  - video                         # Category tags for discovery
  - audio
  - transcription

# ─────────────────────────────────────────────────────────────────────────────
# REQUIREMENTS (Required)
# ─────────────────────────────────────────────────────────────────────────────
requires:
  # Environment variables (checked at runtime)
  env:                            # List of required env vars
    - OPENAI_API_KEY
    - ANTHROPIC_API_KEY
  
  # Optional environment variables (not blocking)
  optional_env:                   # List of optional env vars
    - LANGCHAIN_API_KEY
  
  # Python packages (checked via import)
  packages:                       # List of pip packages
    - praisonaiagents
    - openai>=1.0.0
    - pandas
  
  # External system tools (checked via shutil.which)
  external:                       # List of CLI tools
    - ffmpeg
    - tesseract
    - pandoc
  
  # Recipe tools from praisonai-tools
  tools:                          # List of tool module names
    - llm_tool
    - vision_tool
    - whisper_tool
    - media_tool
    - doc_tool
    - image_tool
    - data_tool
    - chart_tool
    - email_tool

# ─────────────────────────────────────────────────────────────────────────────
# INPUTS (Required)
# ─────────────────────────────────────────────────────────────────────────────
inputs:
  input_field_name:               # Field name (snake_case)
    type: string                  # Type: string, integer, number, boolean, array, object
    description: "Field desc"     # Human-readable description
    required: true                # Whether field is required (default: false)
    default: "default_value"      # Default value if not provided
    enum:                         # Allowed values (optional)
      - option1
      - option2
    minimum: 1                    # For integer/number: minimum value
    maximum: 100                  # For integer/number: maximum value
    pattern: "^[a-z]+$"           # For string: regex pattern

# ─────────────────────────────────────────────────────────────────────────────
# OUTPUTS (Required)
# ─────────────────────────────────────────────────────────────────────────────
outputs:
  output_field_name:              # Field name (snake_case)
    type: string                  # Type: string, integer, number, boolean, array, object
    description: "Field desc"     # Human-readable description

# ─────────────────────────────────────────────────────────────────────────────
# CLI CONFIGURATION (Required)
# ─────────────────────────────────────────────────────────────────────────────
cli:
  command: "praison recipes run my-recipe-name"  # Full command
  examples:                       # List of example invocations
    - 'praison recipes run my-recipe-name --input ''{"field": "value"}'''
    - 'praison recipes run my-recipe-name input.json --output ./out/'
    - 'praison recipes run my-recipe-name --dry-run'

# ─────────────────────────────────────────────────────────────────────────────
# SAFETY CONFIGURATION (Required)
# ─────────────────────────────────────────────────────────────────────────────
safety:
  dry_run_default: false          # If true, --write flag required to execute
  requires_consent: false         # If true, --consent flag required
  consent_message: ""             # Message shown when consent required
  legal_disclaimer: ""            # Legal text shown before execution
  overwrites_files: true          # Whether recipe may overwrite files
  network_access: true            # Whether recipe accesses network
  pii_handling: false             # Whether recipe handles PII data
```

### 4. Runtime Contract

#### Required Entrypoint

Every recipe must have a `recipe.py` with this signature:

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
def run(input_data: dict, config: dict = None) -> dict:
    """
    Execute the recipe.
    
    Args:
        input_data: Dictionary matching the inputs schema from TEMPLATE.yaml
        config: Optional configuration overrides
        
    Returns:
        Dictionary matching the outputs schema from TEMPLATE.yaml
        Must include 'ok' boolean for success/failure indication
    """
    pass
```

#### Standard Output Contract

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# Success response
{
    "ok": True,
    "run_id": "run_abc123",           # Unique run identifier
    "recipe": "my-recipe-name",       # Recipe name
    "output": {                       # Tool-specific output
        "field1": "value1",
        "field2": 123
    },
    "artifacts": [                    # Generated files
        {"path": "output/file.txt", "type": "text", "size_bytes": 1024}
    ],
    "warnings": [],                   # Non-fatal warnings
    "error": None
}

# Error response
{
    "ok": False,
    "run_id": "run_abc123",
    "recipe": "my-recipe-name",
    "output": None,
    "artifacts": [],
    "warnings": [],
    "error": {
        "code": "MISSING_DEPENDENCY",
        "message": "ffmpeg not found",
        "details": "Install with: brew install ffmpeg",
        "retriable": False
    }
}
```

### 5. SDK Reference for Recipe Authors

#### Core Imports from praisonaiagents

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# Agent - The primary agent class
from praisonaiagents import Agent

Agent(
    name="Agent Name",              # Required: Display name
    role="Role Description",        # Agent's role
    goal="What agent aims to do",   # Agent's goal
    instructions="...",             # System instructions
    llm="gpt-4o-mini",              # LLM model to use
    tools=[],                       # List of tools
                       # Enable verbose output
    reflection=False,             # Enable self-reflection
    max_iterations=3,                  # Max reflection iterations
    min_iterations=1,                  # Min reflection iterations
)

# Task - Define work for agents
from praisonaiagents import Task

Task(
    name="task_name",               # Task identifier
    description="What to do",       # Task description
    expected_output="Expected",     # What output should look like
    agent=agent,                    # Agent to execute task
    tools=[],                       # Task-specific tools
    context=[],                     # Context from other tasks
    async_execution=False,          # Run asynchronously
    output_file="output.txt",       # Save output to file
    output_json=MyModel,            # Pydantic model for output
)

# Agents - Orchestrator
from praisonaiagents import AgentTeam

agents = AgentTeam(
    agents=[agent1, agent2],        # List of agents
    tasks=[task1, task2],           # List of tasks
    process="sequential",           # "sequential" or "hierarchical"
                       # Enable verbose output
)
result = agents.start()             # Execute all tasks

# Tool decorator
from praisonaiagents import tool

@tool
def my_tool(param: str) -> str:
    """Tool description for LLM."""
    return f"Result: {param}"
```

#### Recipe Tools from praisonai-tools

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# Install: pip install praisonai-tools

# LLM Tool - Unified LLM interface
from praisonai_tools.recipe_tools import LLMTool, llm_complete

llm = LLMTool(provider="openai", model="gpt-4o-mini")
response = llm.complete("prompt", system="system prompt", max_tokens=1000)
# response.content, response.model, response.usage

# Vision Tool - Image analysis
from praisonai_tools.recipe_tools import VisionTool, vision_caption

vision = VisionTool(provider="openai")
result = vision.analyze("image.jpg", prompt="Describe this")
# result.description, result.tags

# Chart Tool - Visualization
from praisonai_tools.recipe_tools import ChartTool, chart_bar

chart = ChartTool()
result = chart.bar({"A": 10, "B": 20}, title="Chart", output="chart.png")
# result.path

# Media Tool - Audio/Video
from praisonai_tools.recipe_tools import MediaTool, media_probe

media = MediaTool()
info = media.probe("video.mp4")
# info.duration, info.format, info.streams

# Whisper Tool - Transcription
from praisonai_tools.recipe_tools import WhisperTool, whisper_transcribe

whisper = WhisperTool()
transcript = whisper.transcribe("audio.mp3", language="en")
# transcript.text, transcript.segments

# Doc Tool - Document processing
from praisonai_tools.recipe_tools import DocTool, doc_extract_text

doc = DocTool()
text = doc.extract_text("document.pdf")

# Email Tool - Email parsing
from praisonai_tools.recipe_tools import EmailTool, email_parse

email = EmailTool()
parsed = email.parse("message.eml")
# parsed.sender, parsed.subject, parsed.body

# Data Tool - Data processing
from praisonai_tools.recipe_tools import DataTool, data_profile

data = DataTool()
profile = data.profile("data.csv")
# profile.columns, profile.row_count

# Check dependencies
deps = llm.check_dependencies()
# {"openai": True, "api_key": True}
```

### 6. CLI Reference

#### All Commands

```bash theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# List all recipes
praison recipes list
praison recipes list --json
praison recipes list --group

# Show recipe details
praison recipes info <recipe-name>
praison recipes info <recipe-name> --json

# Check dependencies
praison recipes doctor <recipe-name>

# Run a recipe
praison recipes run <recipe-name> <input>
praison recipes run <recipe-name> --input '{"key": "value"}'
praison recipes run <recipe-name> --input-file input.json
praison recipes run <recipe-name> --output ./output/
praison recipes run <recipe-name> --dry-run
praison recipes run <recipe-name> --write          # For dry-run-default recipes
praison recipes run <recipe-name> --consent        # For consent-required recipes
praison recipes run <recipe-name> --force          # Ignore missing deps
praison recipes run <recipe-name> --skip-checks    # Skip all checks
praison recipes run <recipe-name> --json           # JSON output

# Explain execution plan
praison recipes explain <recipe-name>

# Initialize recipe locally
praison recipes init <recipe-name>
praison recipes init <recipe-name> --output ./my-copy/
praison recipes init <recipe-name> --force
praison recipes init <recipe-name> --dry-run
```

#### CLI Flags Reference

| Flag             | Commands        | Description                      |
| ---------------- | --------------- | -------------------------------- |
| `--json`         | list, info, run | Output as JSON                   |
| `--group`        | list            | Group recipes by category        |
| `--input`        | run             | JSON input string                |
| `--input-file`   | run             | Path to JSON input file          |
| `--output`, `-o` | run, init       | Output directory                 |
| `--dry-run`      | run, init       | Show what would be done          |
| `--write`        | run             | Execute dry-run-default recipes  |
| `--consent`      | run             | Acknowledge consent requirements |
| `--force`        | run, init       | Force execution/overwrite        |
| `--skip-checks`  | run             | Skip dependency checks           |

### 7. Testing Patterns

```python theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# test_recipe.py
import pytest
from recipe import run

# Unit test - fast, no API calls
def test_input_validation():
    """Test that missing required fields raise errors."""
    with pytest.raises(ValueError):
        run({})

def test_output_structure():
    """Test output has required fields."""
    result = run({"input": "test"})
    assert "ok" in result
    assert "output" in result

# Integration test - with real APIs
@pytest.mark.integration
def test_with_real_api():
    """Test with actual API calls."""
    result = run({"input": "real data"})
    assert result["ok"] is True

# Mark slow tests
@pytest.mark.slow
def test_large_file_processing():
    """Test with large files."""
    pass

# Run tests
# pytest test_recipe.py                    # Unit tests only
# pytest test_recipe.py -m integration     # Integration tests
# pytest test_recipe.py -m "not slow"      # Skip slow tests
```

### 8. Distribution & Packaging

```yaml theme={"theme":{"light":"vitesse-light","dark":"vitesse-dark"}}
# TEMPLATE.yaml metadata for distribution
name: my-recipe
version: "1.0.0"
author: "Your Name <email@example.com>"
license: "MIT"                    # SPDX identifier
repository: "https://github.com/user/repo"
homepage: "https://example.com"
keywords:
  - ai
  - automation
```

To share a recipe:

1. Create a Git repository with the recipe directory structure
2. Users clone/copy to `~/.praisonai/templates/`
3. Or publish to a recipe registry (future feature)

### 9. Troubleshooting Matrix

| Issue                 | Cause                         | Solution                                |
| --------------------- | ----------------------------- | --------------------------------------- |
| Recipe not discovered | Wrong location                | Move to `~/.praisonai/templates/`       |
| Recipe not discovered | Missing TEMPLATE.yaml         | Create valid TEMPLATE.yaml              |
| Missing dependency    | Package not installed         | `pip install <package>`                 |
| Missing dependency    | External tool missing         | Install system tool (ffmpeg, tesseract) |
| Env var missing       | Not set                       | `export VAR_NAME=value`                 |
| Tool import failure   | praisonai-tools not installed | `pip install praisonai-tools`           |
| Runtime error         | Invalid input                 | Check input against schema              |
| Dry-run mode          | dry\_run\_default=true        | Use `--write` flag                      |
| Consent required      | requires\_consent=true        | Use `--consent` flag                    |

### 10. AI Recipe Author Prompt

Use this prompt to instruct an AI to create a valid recipe:

```
You are creating a PraisonAI recipe. Follow these rules exactly:

1. Create a directory with the recipe name (kebab-case)
2. Create TEMPLATE.yaml with ALL required fields:
   - name, version, description, author, license
   - tags (at least one)
   - requires (env, packages, tools as needed)
   - inputs (with type, description, required for each)
   - outputs (with type, description for each)
   - cli (command and examples)
   - safety (dry_run_default, requires_consent, overwrites_files)

3. Create recipe.py with:
   - def run(input_data: dict, config: dict = None) -> dict
   - Validate all required inputs
   - Return dict with 'ok', 'output', 'artifacts', 'warnings', 'error'
   - Handle errors gracefully

4. Create README.md with:
   - Title and description
   - Quick start example
   - Inputs table
   - Outputs table
   - Requirements
   - Troubleshooting

5. Create test_recipe.py with:
   - Unit tests for input validation
   - Integration tests marked with @pytest.mark.integration

6. Use praisonaiagents for Agent, Task, Agents
7. Use praisonai_tools.recipe_tools for LLMTool, VisionTool, etc.
8. Always check dependencies before using tools
9. Use semantic versioning for version field
10. Include proper error handling and logging
```

***

**Source Files Reference**:

* CLI: `praisonai/cli/features/recipes.py`
* Tools: `praisonai_tools/recipe_tools/__init__.py`
* Core SDK: `praisonaiagents/__init__.py`
* Templates: `Agent-Recipes/agent_recipes/templates/*/TEMPLATE.yaml`
