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

# Channel-aware Prompts

> Customize persona and skill instructions for voice vs text channels

## What Are Channel-aware Prompts?

Channel-aware prompts let you customize your agent's `persona` and skill `context` based on whether the user is interacting via **voice** or **text**.

This is rarely needed — the platform handles most channel-specific behavior automatically. But when you have genuinely different communication needs (e.g., conversational tone on voice, structured lists on text), this feature lets you optimize for each channel.

<Card title="Rule of thumb:" icon="lightbulb">
  If you need to ask "should I say this differently on voice vs text?", you probably don't need channel-aware prompts. Most agents should keep a simple string persona and context.
</Card>

## When to Use Channel-aware Prompts

Use the polymorphic form **only if you have a measurably different need**:

<CardGroup cols={2}>
  <Card title="✅ Use it for:" icon="check">
    * Conversational tone on voice, structured formatting on text
    * Voice-specific instructions (e.g., "avoid markdown")
    * Text-specific instructions (e.g., "use ::: list-item blocks")
  </Card>

  <Card title="❌ Don't use it for:" icon="x">
    * Minor tweaks or polish
    * The same concept explained differently
    * Most agents (keep it simple)
  </Card>
</CardGroup>

## Syntax

Both `persona` and skill `context` accept the polymorphic form:

```typescript theme={null}
// String form (recommended)
persona: "You are Alex, a friendly customer support agent"

// Object form (channel-aware)
persona: {
  base: "You are Alex, a customer support agent.",
  voice: "Speak naturally and conversationally.",
  text: "Use ::: list-item blocks when showing options."
}
```

### Fields

* **`base`** — Shared across all channels (optional)
* **`voice`** — Voice-specific additions (optional, ignored on text)
* **`text`** — Text-specific additions (optional, ignored on voice)

**Strict semantics:** If a channel-specific key isn't set, it is not rendered. There is **no fallback** across channels.

<Note>
  **Validation:** The object must have at least one non-empty field. Empty objects (`{}`), empty strings (`""`), and objects whose only present fields are empty (`{ base: "" }`) are rejected at push time — pass `undefined` or omit the field entirely if you want no persona / context.
</Note>

## Examples

### Example 1: Customer Support Agent

```typescript theme={null}
import { LuaAgent, LuaSkill } from 'lua-cli';

const agent = new LuaAgent({
  name: 'support-agent',
  
  // Base persona shared across channels
  persona: {
    base: `You are Alex, customer support specialist for TechCorp.
You help users resolve issues and find solutions.

Core responsibilities:
- Answer product questions
- Troubleshoot issues
- Process refunds and returns
- Escalate complex issues`,
    
    voice: `Speak naturally and conversationally.
Use short, clear sentences.
Ask one question at a time.`,
    
    text: `For longer explanations, break them into ::: list-item blocks.
Use the ::: actions component to show next steps.
Be concise but thorough in writing.`
  },
  
  skills: [supportSkill]
});
```

On **voice**, the agent hears:

> "You are Alex... Speak naturally and conversationally. Use short, clear sentences..."

On **text**, the agent sees:

> "You are Alex... For longer explanations, break them into ::: list-item blocks..."

### Example 2: Hotel Booking Agent

```typescript theme={null}
const bookingSkill = new LuaSkill({
  name: 'hotel-booking',
  description: 'Book hotel rooms',
  
  context: {
    base: `Help guests find and book hotel rooms.

Key tools:
- check_availability: Find rooms by date and guest count
- create_reservation: Book a confirmed room
- cancel_reservation: Cancel existing booking`,
    
    voice: `When confirming details on a call, read them back naturally:
"So that's checking in on March 15, checking out on March 18, for 2 guests?"
Ask about special requests naturally (early check-in, late checkout, etc.)`,
    
    text: `After searching for availability, show results using ::: horizontal-list-item
blocks with images for each room. Include price, room type, and amenities.
Confirmation steps should use ::: actions component.`
  },
  
  tools: [checkAvailabilityTool, createReservationTool, cancelReservationTool]
});
```

### Example 3: Analytics Report Skill

```typescript theme={null}
const reportSkill = new LuaSkill({
  name: 'analytics-reports',
  description: 'Generate and share analytics reports',
  
  context: {
    base: `Provide analytics insights using generate_report and share_report tools.
Always ask for date range and metrics before generating.`,
    
    voice: `Speak results conversationally:
"Your revenue this month is $42,000, which is up 15% from last month.
The top product is Widget X with 2,500 units sold."`,
    
    text: `Display reports using ::: list-item components for each metric.
Show charts using ::: images component.
Use ::: links to export or share the report.`
  },
  
  tools: [generateReportTool, shareReportTool]
});
```

## Migration: From String to Object

If you start with a simple string and later realize you need channel-specific behavior, the migration is straightforward:

**Before:**

```typescript theme={null}
const agent = new LuaAgent({
  name: 'my-agent',
  persona: 'You are a helpful assistant.'
});
```

**After:**

```typescript theme={null}
const agent = new LuaAgent({
  name: 'my-agent',
  persona: {
    base: 'You are a helpful assistant.',
    voice: 'Speak conversationally.',
    text: 'Use structured formatting.'
  }
});
```

All existing string personas continue to work unchanged.

## Common Patterns

### Pattern 1: Base + Voice Only

When you only need voice customization (text uses the base):

```typescript theme={null}
persona: {
  base: "Core persona description",
  voice: "Additional voice-specific instructions"
  // text is omitted — uses base on text channels
}
```

On voice: `base + voice`\
On text: `base` (text field is not rendered)

### Pattern 2: Base + Text Only

When you only need text customization (voice uses the base):

```typescript theme={null}
context: {
  base: "General skill context",
  text: "Formatting instructions for text channels"
  // voice is omitted — uses base on voice channels
}
```

On voice: `base` (voice field is not rendered)\
On text: `base + text`

### Pattern 3: Base + Both Channels

Full customization for both channels:

```typescript theme={null}
persona: {
  base: "Shared core personality",
  voice: "Voice-specific tone",
  text: "Text-specific formatting"
}
```

On voice: `base + voice`\
On text: `base + text`

## Best Practices

<Steps>
  <Step title="Start simple">
    Write a single string persona first. Add channel-aware behavior only when you discover a real need.
  </Step>

  <Step title="Use base for shared content">
    Put the core agent personality and responsibilities in `base`. Use `voice` and `text` only for channel-specific nuances.
  </Step>

  <Step title="Voice: conversational">
    On voice, focus on natural language flow, short sentences, and oral clarity.
  </Step>

  <Step title="Text: structured">
    On text, leverage the ::: components (list-item, actions, links, etc.) for visual clarity.
  </Step>

  <Step title="Don't over-optimize">
    Remember: the platform handles 95% of channel-specific behavior for you (voice tone, text formatting rules, etc.). Only use this feature for cases where you genuinely need different core instructions.
  </Step>

  <Step title="Test both channels">
    When using channel-aware prompts, always test in both voice and text to ensure they work as intended.
  </Step>
</Steps>

## API Reference

See the `persona` field in [LuaAgent](/api/luaagent) and `context` field in [LuaSkill](/api/luaskill) for complete type signatures and examples.

## Next Steps

<CardGroup cols={2}>
  <Card title="Persona Guide" icon="user" href="/overview/persona">
    Deep dive into creating effective personas
  </Card>

  <Card title="Skill Guide" icon="puzzle-piece" href="/overview/skill">
    Learn about skill design and context
  </Card>

  <Card title="Text Formatting" icon="text" href="/formatting/overview">
    ::: component syntax for text channels
  </Card>

  <Card title="Voice Channels" icon="microphone" href="/channels/voice">
    How voice calls work in Lua
  </Card>
</CardGroup>
