# Channel Tagging System

Channel tags tell Amigo how your service will be used: over voice, over text, or asynchronously. Those tags drive validation and pick LLM presets suited to each channel's latency and capability profile.

## Overview

Different deployment channels have distinct requirements:

* **Voice** channels need ultra-low latency and restrict which state types you can use.
* **Text** channels support the full feature set at moderate latency.
* **Async** channels (email, API) have relaxed latency requirements and the largest capability surface.

The channel tagging system helps you configure services appropriately and validates configurations before sync.

## Channels

| Channel        | Type  | Typical Use Case                        |
| -------------- | ----- | --------------------------------------- |
| `phone`        | voice | Telephony (PSTN / VoIP - Voice over IP) |
| `web_voice`    | voice | Browser WebRTC                          |
| `mobile_voice` | voice | Mobile app voice                        |
| `sms`          | text  | SMS messaging                           |
| `whatsapp`     | text  | WhatsApp                                |
| `web_chat`     | text  | Web chat widget                         |
| `mobile_chat`  | text  | Mobile app chat                         |
| `email`        | async | Email                                   |
| `api`          | async | Direct API integration                  |

## Channel Profiles

Each channel type has a profile that defines its constraints.

### Voice Channels

* **Max states**: 5
* **Allowed state types**: action, annotation, tool-call
* **Memory retrieval**: disabled
* **Dynamic behaviors**: not supported
* **Recommendation**: configure `keyterms` for transcription accuracy

### Text Channels

* **Max states**: unlimited
* **Allowed state types**: all
* **Memory retrieval**: supported
* **Dynamic behaviors**: supported

### Async Channels

* **Max states**: unlimited
* **Allowed state types**: all
* **Memory retrieval**: supported
* **Dynamic behaviors**: supported
* **Maximum capabilities** with relaxed latency requirements

## Version Set Presets

Presets configure LLM models optimized for each channel type.

| Tier              | Voice                     | Text           | Async           |
| ----------------- | ------------------------- | -------------- | --------------- |
| Standard          | `voice`                   | `text`         | `async`         |
| Premium           | `voice_premium`           | `text_premium` | `async_premium` |
| Economy           | `voice_economy`           | `text_economy` | `async_economy` |
| Ultra-Low         | `voice_ultra_low`         | -              | -               |
| Ultra-Low Premium | `voice_ultra_low_premium` | -              | -               |

### Regional Availability

Some presets use LLMs that are not available in all regions. See [LLM Regional Availability](/developer-guide/getting-started/regions-and-endpoints.md#llm-regional-availability) for the full availability matrix.

{% hint style="warning" %}
**Premium Model Regional Restriction**

The following presets use premium-tier models that are only available in **US** and **EU** regions:

* `text_premium`
* `async`
* `async_premium`

These presets **cannot be deployed** to CA or AU regions. Use economy or standard presets for those regions instead.
{% endhint %}

### Ultra-Low Latency Presets

The `voice_ultra_low` and `voice_ultra_low_premium` presets require **single-state context graphs**.

{% hint style="warning" %}
**Single-State Requirements**

To use ultra-low latency presets:

* All action states must have exactly 1 action.
* All action states must have 0 exit conditions.
* Set `skip_active_memory_retrieval: true`.

This triggers the backend fast path, which **skips the `select_next_action` LLM call** and saves 100-500ms latency per turn.
{% endhint %}

## Tag Format

Services support two tag formats in local JSON/YAML files.

### Simple String Format (Recommended)

```json
{
  "tags": ["phone", "voice_premium"]
}
```

Or in YAML:

```yaml
tags:
  - phone
  - voice_premium
```

### Object Format (Legacy)

```json
{
  "tags": [
    {"key": "phone", "value": null},
    {"key": "voice_premium", "value": null}
  ]
}
```

{% hint style="success" %}
**Use the simple string format** for easier editing. Both formats are automatically converted to the API format during sync.
{% endhint %}

Tags encode two things:

1. **Channel** (e.g., `phone`, `web_chat`): which deployment channel the service runs on.
2. **Preset** (e.g., `voice_premium`, `text`): which LLM configuration to apply.

## Service Environment Tags

Services can be tagged with `dev` or `production` to enforce different validation rules for version set pinning.

### Environment Tag Options

| Tag          | Description                  | Validation Rules                                                                              |
| ------------ | ---------------------------- | --------------------------------------------------------------------------------------------- |
| `dev`        | Development/sandbox services | No version pinning required. Can push directly to `release`.                                  |
| `production` | Production services          | Must have `preview` defined. `release` must match `preview`. All version sets must be pinned. |

### Adding Environment Tags

Add an environment tag alongside your channel tags:

```yaml
tags:
  - phone
  - voice_premium
  - production  # or 'dev'
```

{% hint style="info" %}
**No environment tag?** Services without an environment tag skip environment-specific validation entirely.
{% endhint %}

### Production Service Requirements

When a service is tagged `production`, the following rules are enforced during `forge sync-to-remote`:

1. **Preview version set required**: a `preview` version set must be defined.
2. **Release matches preview**: the `release` configuration must exactly match `preview` (agent version, context graph version, LLM preferences).
3. **Versions pinned**: all version sets (except `edge`) must have explicit pinned version numbers. No `latest`.

**Example validation error:**

```
Service: My Production Service
  ! Production service missing required 'preview' version set.
  ! Release version set does not match preview configuration.
  ! Version set 'release' must have pinned agent version for production services.
```

### Dev Service Flexibility

Services tagged `dev` have no version set restrictions:

* Can use unpinned versions (`latest`) in any version set.
* No `preview` requirement.
* Can push directly to `release` without going through a promotion workflow.

{% hint style="warning" %}
**Use `dev` only for sandbox or development environments.** Production services should always use the `production` tag to enforce proper promotion workflows.
{% endhint %}

## LLM Validation

Service tags drive LLM validation at the version set layer. LLM preferences then have to match the channel and cost expectations for those tags.

### Voice-Optimized LLMs

Voice channels need a low Time-To-First-Token (TTFT) for real-time conversation, so only a subset of available LLMs meet the latency bar. Run `forge channel llm-info --channel phone` to see the current list of voice-optimized models.

{% hint style="danger" %}
**Non-voice-optimized LLMs will cause validation errors** for services with voice channel or voice preset tags. Premium-tier and high-capability models generally have higher latency and are not suitable for voice.
{% endhint %}

### Cost Tier Classifications

LLMs are classified into cost tiers for validation against preset expectations.

| Tier     | Description                                      | Price Range (per 1M input) |
| -------- | ------------------------------------------------ | -------------------------- |
| Economy  | Lightweight, low-cost models optimized for speed | $0.05-$0.40                |
| Standard | Balanced cost and capability                     | $0.25-$2                   |
| Premium  | Highest capability models                        | $1.25-$15                  |

Run `forge channel llm-info` to see the current model-to-tier mapping.

### Validation Rules

| Tag                                                  | Validation                                 | Severity |
| ---------------------------------------------------- | ------------------------------------------ | -------- |
| Voice channel (`phone`, `web_voice`, `mobile_voice`) | Non-voice-optimized LLMs                   | ERROR    |
| Voice preset (`voice`, `voice_premium`, etc.)        | Non-voice-optimized LLMs                   | ERROR    |
| Economy preset (`*_economy`)                         | Premium-tier LLMs                          | ERROR    |
| Premium preset (`*_premium`)                         | Only economy-tier LLMs                     | ERROR    |
| Production environment                               | `release` LLM prefs != `preview`           | ERROR    |
| Empty `llm_model_preferences` (voice)                | System defaults may not be voice-optimized | WARNING  |
| No channel/preset tags                               | LLM preferences cannot be validated        | WARNING  |

### Example Validation Output

```
!! CHANNEL VALIDATION ERRORS !!

  Entity: Cardi (68bb4c7fb3c5a689980b217f)
    ✗ ERROR: Version set 'release' uses non-voice-optimized LLM
      for 'backend.chat_agent_engage_user'.
      Voice preset 'voice' requires voice-optimized LLMs for low latency.

~~ CHANNEL VALIDATION WARNINGS ~~

  Entity: SDK Test Service (689b81e7afdaf934f4b48f81)
    ⚠ WARNING: Version set 'edge' has empty llm_model_preferences.
      System defaults may include non-voice-optimized LLMs.
```

### System Defaults vs Preset Defaults

{% hint style="warning" %}
**Important.** Empty `llm_model_preferences` does NOT use preset defaults. It uses **system defaults**, which may not match your channel or preset requirements.

For voice services, always configure LLM preferences explicitly to make sure voice-optimized models are used.
{% endhint %}

## Validation

Services with channel tags are validated against channel constraints:

* **Preset compatibility**: voice presets only work with voice channels.
* **Regional LLM availability**: presets are validated against the target region's LLM availability.
* **LLM preferences**: voice channels require voice-optimized LLMs, and cost tiers must match preset expectations.
* **Channel constraints**: context graphs are checked against channel profile limits.
* **Keyterms warning**: voice services without `keyterms` trigger a warning.
* **Untagged LLM preferences**: services with LLM preferences but no tags trigger a warning.
* **Errors block sync.** Warnings prompt for confirmation.

### Standalone Validation

Use `forge validate` to check services locally before syncing.

```bash
# Validate all services
forge validate --entity-type service --env production

# Validate all entity types
forge validate --all --env production

# Also check references against remote
forge validate --entity-type service --env production --check-references

# Validate service dependencies against channel constraints
forge validate --entity-type service --env production --check-dependencies
```

This catches issues early without making any changes to the remote.

### Dependency Validation (`--check-dependencies`)

The `--check-dependencies` flag validates that a service's linked assets are compatible with its channel constraints. It's essential for voice services, which have strict latency requirements.

**What gets validated:**

| Check                                | Voice Channels | Severity |
| ------------------------------------ | -------------- | -------- |
| Context graph state count ≤ 5        | ✓              | Warning  |
| No decision/reflection/recall states | ✓              | Error    |
| No active memory retrieval           | ✓              | Warning  |
| No dynamic behaviors applied         | ✓              | Error    |
| Single-state for ultra-low presets   | ✓              | Error    |

**Example output:**

```
── Validating service dependencies ──
  Loaded 12 context graphs
  Loaded 148 dynamic behaviors

  Service: Cardi
    Context graph: Cardi POC Check In
    ! Context graph 'Cardi POC Check In' contains state types not allowed
      for phone channel: decision (1), reflection (1).
    ~ Context graph 'Cardi POC Check In' has 10 states, exceeds recommended
      max of 5 for phone channel.

  Service: Reactive Support
    Dynamic behaviors applied: 145
    ! Voice channel 'phone' does not support dynamic behaviors.

============================================================
Validation complete: 3 error(s), 28 warning(s)
```

{% hint style="warning" %}
**Voice Services with Dynamic Behaviors**

Voice channels do not support dynamic behaviors due to latency requirements. If you have dynamic behaviors applied to a voice service, you must either:

1. Remove the dynamic behaviors from the service, or
2. Change the service to a text or async channel.
   {% endhint %}

### Validation Flow

{% @mermaid/diagram content="%%{init: {"theme": "base", "themeVariables": {"primaryColor": "#D4E2E7", "primaryTextColor": "#100F0F", "primaryBorderColor": "#083241", "lineColor": "#575452", "textColor": "#100F0F", "clusterBkg": "#F1EAE7", "clusterBorder": "#D7D2D0"}}}%%
flowchart TB
Sync\[forge sync-to-remote] --> Check{Has channel tags?}
Check -->|No| LLMWarn{Has LLM prefs?}
LLMWarn -->|Yes| WarnNoTag\[Warning: LLM prefs without tags]
LLMWarn -->|No| Proceed\[Sync proceeds]
WarnNoTag --> Proceed
Check -->|Yes| Validate\[Validate service]

```
Validate --> Preset{Preset matches channel?}
Preset -->|No| Error[Error: blocks sync]
Preset -->|Yes| Region{LLMs available in region?}

Region -->|No| Error
Region -->|Yes| LLMValid{LLM prefs valid?}

LLMValid -->|No| Error
LLMValid -->|Yes| Graph{Context graph valid?}

Graph -->|No| Error
Graph -->|Yes| Keyterms{Voice + no keyterms?}

Keyterms -->|Yes| Warn[Warning: prompts confirmation]
Keyterms -->|No| Proceed

Warn --> Confirm{User confirms?}
Confirm -->|Yes| Proceed
Confirm -->|No| Abort[Sync aborted]" %}
```

## CLI Commands

Use `forge channel` commands to explore and validate configurations.

### List Channels

```bash
forge channel list-channels
```

Shows all supported channels with their profiles.

### List Presets

```bash
# All presets
forge channel list-presets

# Filter by type
forge channel list-presets --type voice

# Show LLM configurations
forge channel list-presets --verbose
```

### Show Channel Profile

```bash
forge channel show-profile phone
```

Displays constraints and recommendations for a specific channel.

### Show Tags

```bash
# Default preset
forge channel show-tags phone

# Specific preset
forge channel show-tags phone --preset voice_premium
```

Outputs the JSON tags to add to your service.

### Validate Preset

```bash
# Validate preset for channel
forge channel validate-preset voice_premium phone

# Validate preset for channel AND region
forge channel validate-preset text_premium web_chat --region ca
```

Checks whether a preset is compatible with a channel, and optionally validates regional LLM availability.

### Validate Context Graph

```bash
# Basic validation
forge channel validate-context-graph phone \
  --state-type action \
  --state-type annotation \
  --state-count 3

# Validate for ultra-low latency
forge channel validate-context-graph phone \
  --state-type action \
  --state-count 1 \
  --single-state-eligible \
  --preset voice_ultra_low
```

Validates context graph characteristics against channel constraints.

### LLM Info

```bash
# All models
forge channel llm-info

# Voice-optimized models
forge channel llm-info --channel phone
```

Shows the LLM catalog with voice-optimized recommendations.

## Best Practices

{% hint style="success" %}
**Voice Channel Optimization**

1. **Use keyterms**: configure domain-specific vocabulary for better transcription.
2. **Minimize states**: keep context graphs under 5 states for voice.
3. **Consider ultra-low presets**: if your workflow is single-state, use `voice_ultra_low` to save 100-500ms.
4. **Avoid memory retrieval**: set `skip_active_memory_retrieval: true` for voice.
   {% endhint %}

{% hint style="info" %}
**Preset Selection Guide**
{% endhint %}

| Scenario                            | Recommended Preset |
| ----------------------------------- | ------------------ |
| Production voice with quality focus | `voice_premium`    |
| High-volume voice, cost-sensitive   | `voice_economy`    |
| Single-state voice flows            | `voice_ultra_low`  |
| Standard text chat                  | `text`             |
| Complex reasoning (email, API)      | `async_premium`    |

## Example: Configuring a Voice Service

1. **Check channel constraints:**

   ```bash
   forge channel show-profile phone
   ```
2. **Get tags for your preset:**

   ```bash
   forge channel show-tags phone --preset voice_premium
   ```
3. **Add tags to your service** in `local/<env>/entity_data/service/<service>.yaml`:

   ```yaml
   tags:
     - phone
     - voice_premium
   ```
4. **Validate locally** (catches issues without touching remote):

   ```bash
   forge validate --entity-type service --env production
   ```
5. **Validate dependencies** (makes sure the context graph is compatible):

   ```bash
   forge validate --entity-type service --env production --check-dependencies
   ```
6. **Preview sync changes:**

   ```bash
   forge sync-to-remote --entity-type service --env production
   ```
7. **Apply changes:**

   ```bash
   forge sync-to-remote --entity-type service --env production --apply
   ```

## Related Documentation

{% content-ref url="/pages/plGBeJQjrNSQTKi7tDnp" %}
[Version Sets & Promotion](/developer-guide/operations/devops/version-sets-best-practices.md)
{% endcontent-ref %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.amigo.ai/developer-guide/operations/devops/channel-tagging.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
