> ## Documentation Index
> Fetch the complete documentation index at: https://docs.ensemble.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Prompt Components

> Reusable AI instructions for Think agents

**Define and version reusable AI prompts as components for consistent reasoning across ensembles.**

## Overview

Prompt components enable you to:

* **Reuse prompts** across multiple agents and ensembles
* **Version prompts** with semantic versioning for reproducibility
* **A/B test** different prompt versions
* **Organize** complex multi-step instructions
* **Deploy** prompts independently from code

## Quick Start

### 1. Create a Prompt Component

Create a prompt file (plain text or Markdown):

```text theme={null}
// prompts/analyze-company.txt
You are a company research specialist. Analyze the provided company information and extract:
- Core business description
- Key products and services
- Market position
- Growth metrics
- Risk factors

Provide analysis in a structured format with clear sections.
```

### 2. Add to Edgit

```bash theme={null}
edgit components add analyze-company prompts/analyze-company.txt prompt
edgit tag create analyze-company v1.0.0
edgit tag set analyze-company production v1.0.0
edgit push --tags --force
```

### 3. Reference in Your Ensemble

```yaml theme={null}
ensemble: company-analyzer

agents:
  - name: analyze
    operation: think
    config:
      provider: anthropic
      model: claude-sonnet-4
      # Reference the prompt component with URI
      prompt: "prompt://analyze-company@v1.0.0"

inputs:
  company_data:
    type: string
    required: true

outputs:
  analysis: ${analyze.output}
```

## URI Format and Versioning

All prompt components use the standardized URI format:

```
prompt://{path}[@{version}]
```

**Format breakdown:**

* `prompt://` - Protocol identifier for prompt components
* `{path}` - Logical path to the prompt (e.g., `analyze-company`, `workflows/extraction/step1`)
* `[@{version}]` - Optional version identifier (defaults to `@latest`)

**Version format**:

* `@latest` - Always uses the most recent version
* `@v1` - Uses latest patch of major version (v1.x.x)
* `@v1.0.0` - Specific semantic version (immutable)
* `@prod` - Custom tag for production versions
* `@staging` - Custom tag for staging versions

### Example URIs

```yaml theme={null}
# Always latest version
prompt: "prompt://analyze-company"
prompt: "prompt://analyze-company@latest"

# Specific semantic version
prompt: "prompt://analyze-company@v1.0.0"
prompt: "prompt://analyze-company@v2.1.3"

# Major/minor version (gets latest patch)
prompt: "prompt://analyze-company@v1"
prompt: "prompt://analyze-company@v1.2"

# Custom tags
prompt: "prompt://analyze-company@prod"
prompt: "prompt://analyze-company@staging"

# Nested paths
prompt: "prompt://workflows/extraction/company-info@v1"
```

## How to Reference in Ensembles

There are three ways to reference prompts in your ensembles:

### 1. URI Format (Recommended)

Use the `prompt://` URI format to reference versioned prompt components:

```yaml theme={null}
ensemble: financial-analyst

agents:
  - name: extract-metrics
    operation: think
    config:
      provider: anthropic
      model: claude-sonnet-4
      temperature: 0.1
      # Reference prompt component
      prompt: "prompt://extract-financial-metrics@v1.0.0"

inputs:
  financials:
    type: string

outputs:
  metrics: ${extract-metrics.output}
```

### 2. Inline Prompt with Variables

For simple operations or during development, use inline prompts with template variables:

```yaml theme={null}
ensemble: query-responder

agents:
  - name: respond
    operation: think
    config:
      provider: anthropic
      model: claude-opus-4
      temperature: 0.7
      # Inline prompt with variable interpolation
      prompt: |
        You are a helpful assistant. Answer the user's question using the provided context.

        User question: {{input.question}}
        Context: {{input.context}}

        Provide a clear and concise answer.

inputs:
  question:
    type: string
  context:
    type: string

outputs:
  response: ${respond.output}
```

### 3. Inline Prompt (No Variables)

For static prompts without variables:

```yaml theme={null}
ensemble: content-analyzer

agents:
  - name: analyze
    operation: think
    config:
      provider: anthropic
      model: claude-sonnet-4
      temperature: 0.3
      prompt: |
        You are a content analyst. Analyze the following text and provide:
        - Main topic
        - Key themes
        - Sentiment (positive/negative/neutral)
        - Word count

        Text: {{input.content}}

inputs:
  content:
    type: string

outputs:
  analysis: ${analyze.output}
```

## Using Prompt Components

### Multi-Step Workflow

```yaml theme={null}
ensemble: document-processor

flow:
  - agent: summarize
  - agent: extract-topics
  - agent: generate-questions

agents:
  - name: summarize
    operation: think
    config:
      provider: anthropic
      model: claude-sonnet-4
      prompt: "prompt://summarize-document@v1"
      temperature: 0.3

  - name: extract-topics
    operation: think
    config:
      provider: anthropic
      model: claude-sonnet-4
      prompt: "prompt://extract-topics@v1"
      temperature: 0.1

  - name: generate-questions
    operation: think
    config:
      provider: anthropic
      model: claude-opus-4
      prompt: "prompt://generate-comprehension-questions@v2"
      temperature: 0.8

outputs:
  summary: ${summarize.output}
  topics: ${extract-topics.output}
  questions: ${generate-questions.output}
```

## Caching and Performance

Prompt components are automatically cached for 1 hour (3600 seconds) after first load.

### Default Caching

```yaml theme={null}
agents:
  - name: analyze
    operation: think
    config:
      prompt: "prompt://analyze-company@v1"
      # Cached for 1 hour automatically
```

### Custom Cache TTL

```yaml theme={null}
agents:
  - name: analyze
    operation: think
    config:
      prompt: "prompt://analyze-company@v1"
      cache:
        ttl: 7200  # 2 hours in seconds

inputs:
  data:
    type: string
```

### Bypass Cache

```yaml theme={null}
agents:
  - name: analyze
    operation: think
    config:
      prompt: "prompt://analyze-company@v1"
      cache:
        bypass: true  # Fresh load every time
```

## Best Practices

### 1. Version Your Prompts

Use semantic versioning to track changes:

```bash theme={null}
# First version
edgit tag create analyze-company v1.0.0

# Improvement
edgit tag create analyze-company v1.1.0

# Major change
edgit tag create analyze-company v2.0.0
```

### 2. Use Production Tags

Create stable version tags for production ensembles:

```bash theme={null}
edgit tag set analyze-company production v1.2.3
```

```yaml theme={null}
# Production ensemble uses stable tag
prompt: "prompt://analyze-company@production"
```

### 3. Test Before Promoting

```yaml theme={null}
ensemble: company-analyzer-test

agents:
  - name: analyze-current
    operation: think
    config:
      prompt: "prompt://analyze-company@latest"

  - name: analyze-production
    operation: think
    config:
      prompt: "prompt://analyze-company@production"
```

### 4. Clear, Specific Instructions

```text theme={null}
# Good: Clear, specific guidance
You are an expert financial analyst. Extract the following from the earnings report:
1. Revenue (include year-over-year growth %)
2. Net income (include margin %)
3. Cash flow from operations
4. Key business metrics specific to this industry

Format as structured JSON.

# Bad: Vague instructions
Analyze the financial data.
```

### 5. Include Examples

```text theme={null}
You are a sentiment analyzer. Classify text sentiment as positive, negative, or neutral.

Examples:
- "I love this product!" → positive
- "Terrible experience" → negative
- "It's okay" → neutral

Text to analyze: {{input.text}}
```

### 6. Organize by Purpose

Use path hierarchies for organization:

```
prompts/
├── extraction/
│   ├── company-info.txt
│   ├── financial-metrics.txt
│   └── contact-details.txt
├── analysis/
│   ├── sentiment.txt
│   └── classification.txt
└── generation/
    ├── summarization.txt
    └── question-generation.txt
```

## Provider-Specific Considerations

### Anthropic (Claude)

Optimized for detailed instructions and reasoning:

```yaml theme={null}
agents:
  - name: analyze
    operation: think
    config:
      provider: anthropic
      model: claude-opus-4
      prompt: "prompt://complex-reasoning@v1"
      temperature: 0.2  # Precise following of instructions
```

### OpenAI (GPT)

Works well with concise instructions:

```yaml theme={null}
agents:
  - name: analyze
    operation: think
    config:
      provider: openai
      model: gpt-4-turbo
      prompt: "prompt://task-instruction@v1"
      temperature: 0.5
```

### Cloudflare Workers AI

Use simpler, shorter prompts:

```yaml theme={null}
agents:
  - name: analyze
    operation: think
    config:
      provider: cloudflare
      model: "@cf/meta/llama-3-8b-instruct"
      prompt: "prompt://simple-task@v1"
      temperature: 0.1
```

## Common Patterns

### Sentiment Analysis

```text theme={null}
// prompts/sentiment-analysis.txt
Analyze the sentiment of the provided text. Return:
- sentiment: positive | negative | neutral | mixed
- confidence: 0-1 (confidence score)
- reasoning: brief explanation

Text: ${input.text}
```

### Information Extraction

```text theme={null}
// prompts/extract-contacts.txt
Extract all contact information from the provided text. Include:
- Names (with titles if available)
- Email addresses
- Phone numbers
- Company affiliations

Return as structured JSON with an array of contacts.

Text: {{input.text}}
```

### Content Summarization

```text theme={null}
// prompts/summarize-content.txt
Summarize the provided content in 2-3 sentences, highlighting the key points.
Focus on the most important information for someone unfamiliar with the topic.

Content: {{input.content}}
```

## Versioning Strategy

### Development Workflow

```bash theme={null}
# 1. Create new version
edgit tag create analyze-company v1.1.0

# 2. Test with staging ensemble
ensemble: analyzer-staging
  agents:
    - name: analyze
      operation: think
      config:
        prompt: "prompt://analyze-company@v1.1.0"

# 3. Promote to production
edgit tag set analyze-company production v1.1.0
```

### Rollback Strategy

```yaml theme={null}
# If v1.1.0 has issues, keep using v1.0.0
ensemble: company-analyzer-stable

agents:
  - name: analyze
    operation: think
    config:
      prompt: "prompt://analyze-company@v1.0.0"
```

## Using ctx API in Agents

When building custom agents with TypeScript handlers, you can access prompts through the `ctx` API:

### ctx.prompts.get(name)

Get the raw prompt text by name:

```typescript theme={null}
// agents/analyzer/index.ts
import type { AgentExecutionContext } from '@ensemble-edge/conductor'

export default async function analyze(ctx: AgentExecutionContext) {
  // Get raw prompt
  const analysisPrompt = await ctx.prompts.get('analyze-company')

  return {
    prompt: analysisPrompt,
    length: analysisPrompt.length
  }
}
```

### ctx.prompts.render(name, vars)

Render a prompt template with variables:

```typescript theme={null}
// agents/analyzer/index.ts
import type { AgentExecutionContext } from '@ensemble-edge/conductor'

export default async function analyzeCompany(ctx: AgentExecutionContext) {
  const { companyData } = ctx.input as { companyData: string }

  // Render prompt with variables
  const rendered = await ctx.prompts.render('analyze-company', {
    company_data: companyData,
    analysis_depth: 'detailed',
    focus_areas: 'products, market, risks'
  })

  return {
    prompt: rendered,
    ready: true
  }
}
```

### Complete Example with AI Call

```typescript theme={null}
// agents/company-analyzer/index.ts
import type { AgentExecutionContext } from '@ensemble-edge/conductor'
import Anthropic from '@anthropic-ai/sdk'

interface AnalysisInput {
  companyData: string
  focusAreas?: string[]
}

export default async function analyzeCompany(ctx: AgentExecutionContext) {
  const { companyData, focusAreas } = ctx.input as AnalysisInput

  // Render prompt with variables
  const prompt = await ctx.prompts.render('analyze-company', {
    company_data: companyData,
    focus_areas: focusAreas?.join(', ') || 'all areas'
  })

  // Use rendered prompt with AI
  const client = new Anthropic({
    apiKey: ctx.env.ANTHROPIC_API_KEY
  })

  const response = await client.messages.create({
    model: 'claude-sonnet-4',
    max_tokens: 2048,
    messages: [{ role: 'user', content: prompt }]
  })

  return {
    analysis: response.content[0].type === 'text' ? response.content[0].text : '',
    prompt_used: prompt
  }
}
```

### Dynamic Prompt Selection

```typescript theme={null}
// agents/dynamic-analyzer/index.ts
import type { AgentExecutionContext } from '@ensemble-edge/conductor'

export default async function analyze(ctx: AgentExecutionContext) {
  const { analysisType, data } = ctx.input as {
    analysisType: 'financial' | 'technical' | 'market'
    data: string
  }

  // Choose prompt based on type
  const promptName = `analyze-${analysisType}`
  const prompt = await ctx.prompts.render(promptName, { data })

  return {
    type: analysisType,
    prompt,
    ready: true
  }
}
```

## Troubleshooting

### Prompt Not Found

**Error**: `Component not found: prompt://analyze-company@v1.0.0`

**Solution**:

1. Check prompt exists: `edgit list prompts`
2. Check version: `edgit tag list analyze-company`
3. Verify deployment: `edgit tag show analyze-company@v1.0.0`

### Inconsistent Results

**Issue**: Same prompt produces different outputs

**Solutions**:

1. Set `temperature: 0` for deterministic results
2. Use specific model versions: `claude-sonnet-4-20250514`
3. Include more specific examples in the prompt

### Cache Issues

**Issue**: Updated prompt not being used

**Solution**: Invalidate cache or set `cache.bypass: true`

```yaml theme={null}
agents:
  - name: analyze
    operation: think
    config:
      prompt: "prompt://analyze-company@latest"
      cache:
        bypass: true
```

## Next Steps

<CardGroup cols={2}>
  <Card title="Query Components" icon="database" href="/conductor/components/queries">
    SQL queries as components
  </Card>

  <Card title="Config Components" icon="gear" href="/conductor/components/configs">
    JSON settings as components
  </Card>

  <Card title="Think Operation" icon="brain" href="/conductor/operations/think">
    AI reasoning operations
  </Card>

  <Card title="Edgit Versioning" icon="code-branch" href="/edgit/guides/versioning-components-agents">
    Version control for components
  </Card>
</CardGroup>
