Skip to content

Skill System

The skill system provides modular, composable capabilities that the AI agent can use to generate responses. Skills are organized by category and can be enabled/disabled per client.

Architecture

Skill Definition

Each skill is defined in a SKILL.md file with YAML frontmatter:

---
name: skill_name
default_enabled: true
description: Brief description for LLM selection
category: response_ending
required: false
emoji: "🎯"
---

# Instructions

Detailed instructions for the LLM...

Skill Examples

Skills use two types of examples to guide LLM behavior:

1. Trigger Examples (Frontmatter)

trigger_examples in the YAML frontmatter help the skill selector LLM decide WHEN to select a skill. Only the first 3 examples are shown in the selection prompt.

trigger_examples:
  - "We're a fintech company"    # Industry signal
  - "What ROI can I expect?"     # Results signal
  - "Do you have case studies?"  # Proof signal

Best practices for trigger_examples:

  • Use semantic variety (different ways to express the same intent)
  • Avoid language-specific phrases; prefer patterns the LLM can generalize
  • Put the most important trigger type first (first 3 are shown to LLM)
  • Match the categories described in the description field

2. Instruction Examples (Body)

The # examples section in the skill body shows the answer LLM HOW to use the skill correctly once selected. Use GOOD/BAD patterns:

# examples

**GOOD - Natural transition to demo:**
**Visitor:** "We're looking to automate our onboarding"
**Agent:** "Automating onboarding can reduce manual work...

👇 Feel free to connect with a Sales expert using the button below."

**BAD - Missing emoji:**
**Agent:** "Feel free to connect with our Sales team."
**Why bad:** Missing 👇 emoji at the beginning of the last sentence.

Best practices for instruction examples:

  • Always explain Why bad for BAD examples
  • Show realistic visitor/agent exchanges
  • Cover edge cases and common mistakes
  • Keep examples generic (not client-specific) in global skills

Skill Categories

Category Purpose Examples
response_ending How to end responses demo_offer, content_gating, context_gathering, clean_ending
response_handling Content generation pricing, competitors, support
system Auto-injected context knowledge_retrieval, visitor_profile, conversation_history

Category Definition (CATEGORY.md)

Each category folder contains a CATEGORY.md file that configures how the category behaves in both the skill selector and the answer writer.

See backend/apps/shared_data/prompts/website-agent/skills/response_ending/CATEGORY.md for a full example.

CATEGORY.md Fields

Fields are consumed by two different LLMs:

Field Consumer Purpose
display_name Answer Writer Heading text in assembled prompt
answer_instructions Answer Writer Instructions shown before skills in main prompt
uncertainty_guidance Answer Writer Shown when multiple skills from category are selected
selector_description Skill Selector Brief description to help LLM understand category
selector_guidance Skill Selector Detailed rules for when to select skills
order Both Sort order for categories (lower = first)
hidden_from_llm Both If true, skills in category are auto-injected by code

How Categories Affect Skill Selection

The selector_guidance field is critical for LLM decision-making. Use it to:

  1. Define defaults: "clean_ending is the DEFAULT for most responses"
  2. Create decision frameworks: List conditions for each skill in priority order
  3. Set exclusivity rules: "content_gating > context_gathering when visitor states industry"
  4. Handle uncertainty: "When uncertain, select BOTH and let the answer LLM decide"

Skill Selection Pipeline

The skill_selector node uses a two-phase pipeline:

LLM Selection → Post-Processing Rules → Final Skills

Phase 1: LLM Selection

The LLM selects skills based on conversation context and skill descriptions.

Phase 2: Post-Processing Rules

Mechanical rules enforce priority and exclusivity:

  1. Ending Rules (priority-based, first match wins):
  2. demo_offer - Priority 1, removes all other ending skills
  3. content_gating - Priority 2, removes context_gathering/clean_ending
  4. context_gathering - Priority 3, can add clean_ending

  5. System Rules (all apply additively):

  6. visitor_profile - Injected if valid company data exists
  7. conversation_history - Injected if turn > 0
  8. knowledge_retrieval - Always injected (RAG context)

Skill Toggles

Skills can be enabled/disabled per client via the skill_toggles column in the agent_config table.

Default Behavior

Skills are ENABLED by default unless they have default_enabled: false in their SKILL.md metadata.

Configuration

-- Enable content_gating for a client
UPDATE agent_config
SET skill_toggles = '{"content_gating": {"enabled": true}}'
WHERE site_domain = 'example.com';

Lookup Cascade

1. agent_config.skill_toggles (explicit toggle)
2. SKILL_DEFAULT_ENABLED (from SKILL.md metadata)
3. True (default - skills enabled unless explicitly disabled)

Content Gating Skill

The content_gating skill enables email capture by offering valuable content in exchange.

How It Works

2-Step Flow:

  1. Turn N (Offer): Agent answers question + offers content with 💌 emoji
  2. Turn N+1 (Capture): Agent asks for email if visitor accepts

Availability States

State Condition Behavior
allowed Enabled, no restrictions Skill can be selected
discouraged Within cooldown period LLM discouraged from selecting
forbidden Disabled OR email captured Skill removed from selection

Cooldown Logic

After offering content (Turn N): - Turn N+1: Allowed (must handle visitor response) - Turn N+2 to N+3: Discouraged (cooldown active) - Turn N+4+: Allowed (cooldown passed)

Qualification Criteria

Optional criteria that trigger content gating offers:

UPDATE agent_config
SET qualification_criteria = '["number of support agents", "current tool"]'
WHERE site_domain = 'example.com';

When visitors mention these criteria, the LLM is more likely to offer relevant content.

Adding New Skills

1. Create SKILL.md

mkdir -p backend/apps/shared_data/prompts/website-agent/skills/{category}/{skill_name}/
---
name: my_skill
default_enabled: true
description: When to use this skill
category: response_ending
emoji: "🎯"
---

# Instructions

Your skill instructions here...

2. Add Post-Processing Rules (if needed)

For ending skills with priority/exclusivity rules, update skill_selector.py:

ENDING_RULES = [
    _rule_demo_offer,
    _rule_content_gating,
    _rule_my_skill,  # Add new rule
    _rule_context_gathering,
]

3. Add Default Toggle (if disabled by default)

# In agent_config.py
SKILL_DEFAULT_ENABLED: dict[str, bool] = {
    "content_gating": False,
    "my_skill": False,  # Requires explicit enablement
}

4. Test

poetry run pytest packages/ixchat/tests/test_skill_selector.py -v