Skip to content

Building a Production AI Copilot

A step-by-step guide to building a production-grade AI copilot that combines streaming chat, rich UIs, RAG knowledge, tool use, memory, multi-agent orchestration, and multi-protocol exposure — all in declarative YAML. From zero to a deployed, multi-agent copilot in 12 incremental steps.


Table of Contents

  1. What is a Copilot?
  2. Architecture Overview
  3. Step 1 — Core Chat Agent
  4. Step 2 — Streaming Chat Frontend (AG-UI)
  5. Step 3 — Rich Declarative UIs (A2UI)
  6. Step 4 — RAG Knowledge Base
  7. Step 5 — Memory and Session Persistence
  8. Step 6 — Tool Integration
  9. Step 7 — MCP Tool Server Integration
  10. Step 8 — Multi-Agent Orchestration
  11. Step 9 — Security and Authentication
  12. Step 10 — Multi-Protocol Exposure
  13. Step 11 — Observability and Quality Monitoring
  14. Step 12 — Production Deployment
  15. Complete Copilot — Full YAML Reference
  16. Copilot Patterns
  17. Frontend Integration Guide

1. What is a Copilot?

A copilot is an AI assistant embedded into an application that helps users accomplish tasks through natural language conversation. Unlike a simple chatbot, a production copilot needs:

  • Streaming responses — Real-time token-by-token delivery for responsive UX
  • Knowledge grounding — RAG over domain-specific documents to prevent hallucination
  • Tool use — Ability to search, query databases, call APIs, read/write files
  • Memory — Conversation history within sessions and semantic recall across sessions
  • Multi-agent reasoning — Specialist agents for different domains, coordinated by a supervisor
  • Rich UI rendering — Beyond text: cards, buttons, forms, data tables, charts
  • Multi-protocol access — Chat frontend, Claude Desktop (MCP), other agents (A2A)
  • Security — Authentication, authorization, rate limiting, tenant isolation
  • Observability — Metrics, tracing, quality evaluation, alerting

Helix provides all of these as declarative YAML configuration. No Go code required.


2. Architecture Overview

                                    ┌─────────────────────────────┐
                                    │     Helix Copilot Engine    │
                                    │                             │
  ┌──────────────┐    AG-UI (SSE)   │  ┌───────────────────────┐  │
  │ Chat Frontend│◄────────────────►│  │  Supervisor Agent     │  │
  │ (CopilotKit) │                  │  │  ┌─────┐ ┌─────────┐  │  │
  └──────────────┘                  │  │  │ReAct│ │Plan-Exec│  │  │
                                    │  │  │Agent│ │ Agent   │  │  │
  ┌──────────────┐    A2UI (SSE)    │  │  └──┬──┘ └────┬────┘  │  │
  │ Rich UI App  │◄────────────────►│  │     │         │       │  │
  │ (Google A2UI)│                  │  └─────┼─────────┼───────┘  │
  └──────────────┘                  │        │         │          │
                                    │  ┌─────▼─────────▼───────┐  │
  ┌──────────────┐    MCP (HTTP)    │  │       Tool Layer       │  │
  │Claude Desktop│◄────────────────►│  │ ┌────┐┌────┐┌──────┐  │  │
  │  / Cursor    │                  │  │ │RAG ││MCP ││HTTP  │  │  │
  └──────────────┘                  │  │ │Tool││Tool││Tools │  │  │
                                    │  │ └──┬─┘└──┬─┘└──┬───┘  │  │
  ┌──────────────┐    A2A (JSON-RPC)│  └────┼─────┼─────┼──────┘  │
  │ Other Agents │◄────────────────►│       │     │     │         │
  │ (A2A clients)│                  │  ┌────▼─────▼─────▼──────┐  │
  └──────────────┘                  │  │   Knowledge Layer      │  │
                                    │  │ ┌────────┐ ┌────────┐  │  │
  ┌──────────────┐    REST (HTTP)   │  │ │pgvector│ │External│  │  │
  │  REST API    │◄────────────────►│  │ │  RAG   │ │MCP Svrs│  │  │
  │  Clients     │                  │  │ └────────┘ └────────┘  │  │
  └──────────────┘                  │  │ ┌────────┐ ┌────────┐  │  │
                                    │  │ │Composite│ │ Graph  │  │  │
                                    │  │ │ Memory  │ │  KG    │  │  │
                                    │  │ └────────┘ └────────┘  │  │
                                    │  └───────────────────────┘  │
                                    └─────────────────────────────┘

Protocol Endpoints:

Protocol Port Purpose Client
AG-UI 4100 Streaming chat (SSE) CopilotKit, custom frontends
A2UI 4200 Rich declarative UIs (SSE) Google A2UI renderers
MCP 3000 Tool exposure (HTTP/SSE/stdio) Claude Desktop, Cursor, IDEs
A2A 9000 Agent-to-agent (JSON-RPC) Other AI agents
HTTP 8080 REST API Mobile apps, scripts, webhooks

3. Step 1 — Core Chat Agent

Start with a single ReAct agent that forms the copilot brain.

agents:
  - id: copilot
    type: react
    trigger: http-server://0.0.0.0:8080/api/chat
    model:
      provider: anthropic
      model: claude-sonnet-4-20250514
      api_key: "${env:ANTHROPIC_API_KEY}"
      temperature: 0.4
      max_tokens: 2048
    system_prompt: |
      You are a helpful AI copilot for [Your Company].
      You assist users with questions about our products,
      documentation, and internal processes.

      Guidelines:
      - Be concise and direct
      - Cite sources when referencing documents
      - If you don't know something, say so honestly
      - Suggest follow-up actions when appropriate
    max_iterations: 8

Run it:

helix run copilot.yaml

Test it:

curl -X POST http://localhost:8080/api/chat \
  -H "Content-Type: application/json" \
  -d '{"body": "What can you help me with?"}'

4. Step 2 — Streaming Chat Frontend (AG-UI)

Replace the HTTP endpoint with AG-UI for real-time streaming to CopilotKit or any SSE-capable frontend.

agents:
  - id: copilot
    type: react
    trigger: agui://0.0.0.0:4100/api/chat?name=copilot&corsOrigin=*
    model:
      provider: anthropic
      model: claude-sonnet-4-20250514
      api_key: "${env:ANTHROPIC_API_KEY}"
      temperature: 0.4
      max_tokens: 2048
    system_prompt: |
      You are a helpful AI copilot. Provide clear, well-structured
      answers. Use markdown formatting for readability.

      When you finish answering, suggest 2-3 relevant follow-up
      questions the user might want to ask.
    max_iterations: 8

How AG-UI Streaming Works

  1. Frontend sends a POST with RunAgentInput (thread ID, messages, tools, state)
  2. Helix extracts the last user message and runs it through the agent
  3. The agent's LLM response streams back as SSE events:
event: RUN_STARTED
data: {"type":"RUN_STARTED","threadId":"t-123","runId":"r-456"}

event: TEXT_MESSAGE_START
data: {"type":"TEXT_MESSAGE_START","messageId":"m-789","role":"assistant"}

event: TEXT_MESSAGE_CONTENT
data: {"type":"TEXT_MESSAGE_CONTENT","messageId":"m-789","delta":"Here's "}

event: TEXT_MESSAGE_CONTENT
data: {"type":"TEXT_MESSAGE_CONTENT","messageId":"m-789","delta":"what I found..."}

event: TEXT_MESSAGE_END
data: {"type":"TEXT_MESSAGE_END","messageId":"m-789"}

event: RUN_FINISHED
data: {"type":"RUN_FINISHED","threadId":"t-123","runId":"r-456"}

CopilotKit Integration

import { CopilotKit } from "@copilotkit/react-core";
import { CopilotChat } from "@copilotkit/react-ui";

function App() {
  return (
    <CopilotKit runtimeUrl="http://localhost:4100/api/chat">
      <CopilotChat
        labels={{ title: "AI Copilot", initial: "How can I help?" }}
      />
    </CopilotKit>
  );
}

5. Step 3 — Rich Declarative UIs (A2UI)

Add A2UI for rendering rich interactive surfaces — cards, buttons, forms, tables — alongside the chat stream.

agents:
  # Chat endpoint (AG-UI)
  - id: copilot
    type: react
    trigger: agui://0.0.0.0:4100/api/chat?name=copilot&corsOrigin=*
    model:
      provider: anthropic
      model: claude-sonnet-4-20250514
      api_key: "${env:ANTHROPIC_API_KEY}"
      temperature: 0.4
    system_prompt: "You are a helpful copilot."
    max_iterations: 8

  # Rich UI surface endpoint (A2UI)
  - id: ui-agent
    type: react
    trigger: a2ui://0.0.0.0:4200/api/surface?name=copilot-ui&corsOrigin=*
    model:
      provider: openai
      model: gpt-4o
      api_key: "${env:OPENAI_API_KEY}"
      temperature: 0.3
    system_prompt: |
      You create rich UI responses. When the user asks for data,
      format your response as structured JSON that can be rendered
      as cards, tables, or interactive elements.
    max_iterations: 5

A2UI Protocol

GET — Stream UI surface updates:

GET /api/surface?message=Show+me+recent+orders&surface=main

Response (SSE JSONL):

{"beginRendering": {"surfaceId": "main", "root": "root"}}
{"updateComponents": {"surfaceId": "main", "components": [
  {"id": "root", "type": "Column", "children": ["card-1"]},
  {"id": "card-1", "type": "Card", "children": ["title", "content"]},
  {"id": "title", "type": "TextStatic", "properties": {"text": "Recent Orders"}},
  {"id": "content", "type": "TextStatic", "properties": {"text": "Here are your orders..."}}
]}}

POST — Receive user interactions:

{
  "event": {
    "surfaceId": "main",
    "componentId": "approve-btn",
    "type": "action",
    "data": {"orderId": "ORD-123"}
  }
}


6. Step 4 — RAG Knowledge Base

Ground the copilot in domain-specific knowledge to prevent hallucination.

6.1 Document Ingestion Pipeline

workflows:
  # Nightly full reindex
  - id: copilot-ingest-full
    trigger:
      uri: cron://nightly?schedule=0 2 * * *
    steps:
      - rag-ingest:
          reader: directory
          path: ./knowledge-base
          recursive: true
          extensions:
            - ".md"
            - ".pdf"
            - ".html"
            - ".txt"
            - ".docx"
      - rag-chunk:
          strategy: semantic
          threshold: 0.45
          chunk_size: 1000
          overlap: 150
      - rag-embed:
          provider: openai
          model: text-embedding-3-small
          api_key: "${env:OPENAI_API_KEY}"
      - rag-store:
          store: pgvector
          connection: "${env:DATABASE_URL}"
          collection: copilot_knowledge
          dimensions: 1536
      # Extract metadata for filtering
      - rag-extract:
          extractors:
            - title
            - keywords
            - summary
          model:
            provider: openai
            model: gpt-4o-mini
            api_key: "${env:OPENAI_API_KEY}"
      - target: log://ingestion?level=info

  # Hourly incremental updates
  - id: copilot-ingest-incremental
    trigger:
      uri: cron://hourly?schedule=0 * * * *
    steps:
      - rag-ingest:
          reader: directory
          path: ./knowledge-base
          recursive: true
      - filter:
          starlang: |
            import "time"
            modified = headers["HelixFileLastModified"]
            modified > time.now() - time.hour
      - rag-chunk:
          strategy: semantic
          threshold: 0.45
          chunk_size: 1000
          overlap: 150
      - rag-embed:
          provider: openai
          model: text-embedding-3-small
          api_key: "${env:OPENAI_API_KEY}"
      - rag-store:
          store: pgvector
          connection: "${env:DATABASE_URL}"
          collection: copilot_knowledge

6.2 Copilot with RAG Tools

Now give the agent search tools to query the knowledge base:

agents:
  - id: copilot
    type: react
    trigger: agui://0.0.0.0:4100/api/chat?name=copilot&corsOrigin=*
    model:
      provider: anthropic
      model: claude-sonnet-4-20250514
      api_key: "${env:ANTHROPIC_API_KEY}"
      temperature: 0.4
      max_tokens: 2048
    system_prompt: |
      You are a helpful copilot with access to a knowledge base.

      WORKFLOW:
      1. When the user asks a question, search the knowledge base first
      2. Use search_knowledge for standard queries
      3. Use search_diverse when you need broader perspectives
      4. Synthesize your answer from the retrieved documents
      5. Always cite which documents support your claims
      6. If the knowledge base doesn't have the answer, say so honestly

      Format responses with markdown for readability.
    tools:
      - name: search_knowledge
        type: rag-query
        description: "Search the knowledge base for information. Use specific, targeted queries."
        parameters:
          type: object
          properties:
            query:
              type: string
              description: "Specific search query"
            top_k:
              type: integer
              default: 5
              description: "Number of results to retrieve"
          required:
            - query
        config:
          store: pgvector
          connection: "${env:DATABASE_URL}"
          collection: copilot_knowledge
          retriever: hybrid
          alpha: 0.7

      - name: search_diverse
        type: rag-query
        description: "Search with diversity emphasis for broader coverage. Use when standard search returns too-similar results."
        parameters:
          type: object
          properties:
            query:
              type: string
            top_k:
              type: integer
              default: 8
        config:
          store: pgvector
          connection: "${env:DATABASE_URL}"
          collection: copilot_knowledge
          retriever: mmr
          lambda: 0.3
          fetch_k: 25
    max_iterations: 8

6.3 Multi-Collection RAG

For copilots with multiple knowledge domains:

          tools:
            - name: search_product_docs
              type: rag-query
              description: "Search product documentation, features, and guides"
              parameters:
                type: object
                properties:
                  query:
                    type: string
                  top_k:
                    type: integer
                    default: 5
              config:
                store: pgvector
                connection: "${env:DATABASE_URL}"
                collection: product_docs
                retriever: hybrid
                alpha: 0.7

            - name: search_api_reference
              type: rag-query
              description: "Search API documentation and code examples"
              parameters:
                type: object
                properties:
                  query:
                    type: string
                  top_k:
                    type: integer
                    default: 5
              config:
                store: pgvector
                connection: "${env:DATABASE_URL}"
                collection: api_docs
                retriever: hybrid
                alpha: 0.8

            - name: search_support_history
              type: rag-query
              description: "Search past support tickets for similar issues and resolutions"
              parameters:
                type: object
                properties:
                  query:
                    type: string
                  top_k:
                    type: integer
                    default: 5
              config:
                store: pgvector
                connection: "${env:DATABASE_URL}"
                collection: support_tickets
                retriever: hybrid
                alpha: 0.5

            - name: search_internal_wiki
              type: rag-query
              description: "Search internal wiki for processes, policies, and team knowledge"
              parameters:
                type: object
                properties:
                  query:
                    type: string
                  top_k:
                    type: integer
                    default: 5
              config:
                store: pgvector
                connection: "${env:DATABASE_URL}"
                collection: internal_wiki
                retriever: mmr
                lambda: 0.5

7. Step 5 — Memory and Session Persistence

Add memory so the copilot remembers conversation context and can recall past interactions.

7.1 Basic Session Memory

          memory:
            enabled: true
            type: sliding-window
            window_size: 30
            session_id_header: "X-Session-ID"

The session_id_header is critical for multi-user copilots — each user gets isolated memory. The frontend must send the session ID as a header with each request.

7.2 Persistent Cross-Session Memory

          memory:
            enabled: true
            type: sql-long-term
            dsn: "${env:DATABASE_URL}"
            session_id_header: "X-Session-ID"

This stores all conversation history in PostgreSQL. Conversations survive server restarts.

Combine multiple memory types for the best of all worlds:

          memory:
            enabled: true
            type: composite
            session_id_header: "X-Session-ID"
            backends:
              # Recent context: last 25 messages for immediate conversation flow
              - type: sliding-window
                window_size: 25

              # Semantic recall: find relevant past conversations by meaning
              - type: vector
                top_k: 5
                embed:
                  provider: openai
                  model: text-embedding-3-small
                  api_key: "${env:OPENAI_API_KEY}"

              # Persistent storage: full history survives restarts
              - type: sql-long-term
                dsn: "${env:DATABASE_URL}"
                session_id_header: "X-Session-ID"

How composite memory works: - Add (new messages): Written to ALL backends simultaneously - Get (conversation history): Merges results from all backends, deduplicates - Search (semantic): Each backend searches independently, results merged

This means the copilot: 1. Always has the last 25 messages for immediate context 2. Can semantically recall relevant past conversations ("as we discussed last week...") 3. Never loses history even if the server restarts

7.4 Memory-Aware System Prompt

Update the system prompt to leverage memory:

          system_prompt: |
            You are a helpful copilot with conversation memory.

            - You remember past conversations with this user
            - Reference relevant past discussions when applicable
            - If the user says "as we discussed" or "remember when",
              check your memory for context
            - Build on previous conversations rather than starting fresh
            - Note: Your sliding window shows the last 25 messages,
              and semantic search finds relevant older conversations

8. Step 6 — Tool Integration

Give the copilot tools to interact with external systems.

8.1 HTTP API Tools

          tools:
            # Existing RAG tools...

            - name: create_ticket
              type: connector
              description: "Create a support ticket in the ticketing system"
              parameters:
                type: object
                properties:
                  title:
                    type: string
                    description: "Ticket title"
                  description:
                    type: string
                    description: "Detailed description of the issue"
                  priority:
                    type: string
                    enum:
                      - low
                      - medium
                      - high
                      - urgent
                  assignee:
                    type: string
                    description: "Team or person to assign to"
                required:
                  - title
                  - description
              config:
                endpoint: "https://api.ticketing.example.com/tickets"
                method: POST
                headers:
                  Authorization: "Bearer ${env:TICKET_API_KEY}"

            - name: lookup_user
              type: connector
              description: "Look up a user's account information by email or ID"
              parameters:
                type: object
                properties:
                  email:
                    type: string
                  user_id:
                    type: string
              config:
                endpoint: "https://api.internal.example.com/users"
                method: GET
                headers:
                  Authorization: "Bearer ${env:INTERNAL_API_KEY}"

            - name: check_system_status
              type: connector
              description: "Check the health status of a system or service"
              parameters:
                type: object
                properties:
                  service:
                    type: string
                    description: "Service name (e.g., api, database, cache)"
              config:
                endpoint: "https://status.example.com/api/services"
                method: GET

8.2 Function Tools (Custom Logic)

          tools:
            - name: calculate
              type: function
              description: "Perform mathematical calculations"
              parameters:
                type: object
                properties:
                  expression:
                    type: string
                    description: "Math expression to evaluate (e.g., '42 * 1.15')"
                required:
                  - expression

            - name: format_date
              type: function
              description: "Convert dates between formats and timezones"
              parameters:
                type: object
                properties:
                  date:
                    type: string
                    description: "Date string to convert"
                  from_format:
                    type: string
                    default: "RFC3339"
                  to_format:
                    type: string
                    default: "2006-01-02"
                  timezone:
                    type: string
                    default: "UTC"

9. Step 7 — MCP Tool Server Integration

Connect the copilot to external MCP tool servers for filesystem, database, and third-party access.

9.1 Consuming MCP Tools

          tools:
            # Import tools from external MCP servers
            - name: filesystem_tools
              type: mcp
              description: "Read and search files on the server"
              mcp_server:
                url: "http://localhost:3001"
                transport: http
                headers:
                  Authorization: "Bearer ${env:MCP_FS_TOKEN}"
                tools:
                  - read_file
                  - list_directory
                  - search_files

            - name: database_tools
              type: mcp
              description: "Query the application database"
              mcp_server:
                url: "http://localhost:3002"
                transport: http
                headers:
                  Authorization: "Bearer ${env:MCP_DB_TOKEN}"
                tools:
                  - query
                  - list_tables
                  - describe_table

            - name: github_tools
              type: mcp
              description: "Interact with GitHub repos, issues, and PRs"
              mcp_server:
                command: "npx"
                args:
                  - "@modelcontextprotocol/server-github"
                transport: stdio
                tools:
                  - search_code
                  - get_file_contents
                  - list_issues
                  - create_issue

9.2 Exposing the Copilot as an MCP Server

Allow Claude Desktop, Cursor, and other MCP clients to use the copilot:

helix:
  mcp:
    server:
      enabled: true
      transport: http
      addr: "0.0.0.0:3000"
      name: "my-copilot"
      version: "1.0.0"
      workflows:
        - copilot-chat
      tools:
        copilot-chat:
          description: "Ask the AI copilot any question about our products and docs"
          input_schema: '{"type":"object","properties":{"query":{"type":"string","description":"Your question"}},"required":["query"]}'

Claude Desktop configuration (claude_desktop_config.json):

{
  "mcpServers": {
    "my-copilot": {
      "url": "http://localhost:3000"
    }
  }
}


10. Step 8 — Multi-Agent Orchestration

Scale the copilot from a single agent to a coordinated team of specialists.

10.1 Supervisor with Specialist Agents

agents:
  - id: copilot-chat
    type: supervisor
    trigger: agui://0.0.0.0:4100/api/chat?name=copilot&corsOrigin=*
    model:
      provider: anthropic
      model: claude-sonnet-4-20250514
      api_key: "${env:ANTHROPIC_API_KEY}"
      temperature: 0.3
    system_prompt: |
      You are the copilot supervisor. Route user questions to the
      most appropriate specialist agent:

      - product_expert: Product features, pricing, capabilities, comparisons
      - technical_support: Bugs, errors, configuration, troubleshooting
      - api_developer: API usage, code examples, SDK integration, webhooks
      - account_manager: Billing, subscriptions, account settings, team management

      For questions spanning multiple domains, route to the primary domain
      first. If the answer is incomplete, route to additional specialists.
    memory:
      enabled: true
      type: composite
      session_id_header: "X-Session-ID"
      backends:
        - type: sliding-window
          window_size: 25
        - type: sql-long-term
          dsn: "${env:DATABASE_URL}"
          session_id_header: "X-Session-ID"

    sub_agents:
      - id: product_expert
        type: react
        model:
          provider: anthropic
          model: claude-sonnet-4-20250514
          api_key: "${env:ANTHROPIC_API_KEY}"
          temperature: 0.4
        system_prompt: |
          You are a product expert. Search the product documentation to
          answer questions about features, pricing, and capabilities.
          Be specific, cite documentation, and suggest relevant features
          the user might not know about.
        tools:
          - name: search_product
            type: rag-query
            description: "Search product documentation"
            parameters:
              type: object
              properties:
                query:
                  type: string
                top_k:
                  type: integer
                  default: 5
            config:
              store: pgvector
              connection: "${env:DATABASE_URL}"
              collection: product_docs
              retriever: hybrid
              alpha: 0.7
        max_iterations: 5

      - id: technical_support
        type: react
        model:
          provider: openai
          model: gpt-4o
          api_key: "${env:OPENAI_API_KEY}"
          temperature: 0.2
        system_prompt: |
          You are a technical support specialist. Diagnose issues
          methodically. Search both documentation and past support
          tickets. Provide step-by-step solutions. If the issue
          requires escalation, recommend creating a support ticket.
        tools:
          - name: search_docs
            type: rag-query
            description: "Search technical documentation and troubleshooting guides"
            parameters:
              type: object
              properties:
                query:
                  type: string
                top_k:
                  type: integer
                  default: 5
            config:
              store: pgvector
              connection: "${env:DATABASE_URL}"
              collection: technical_docs
              retriever: hybrid
              alpha: 0.7
          - name: search_tickets
            type: rag-query
            description: "Search past support tickets for similar issues"
            parameters:
              type: object
              properties:
                query:
                  type: string
                top_k:
                  type: integer
                  default: 5
            config:
              store: pgvector
              connection: "${env:DATABASE_URL}"
              collection: support_tickets
              retriever: hybrid
              alpha: 0.5
          - name: create_ticket
            type: connector
            description: "Escalate by creating a support ticket"
            parameters:
              type: object
              properties:
                title:
                  type: string
                description:
                  type: string
                priority:
                  type: string
                  enum: [low, medium, high, urgent]
              required: [title, description]
            config:
              endpoint: "https://api.ticketing.example.com/tickets"
              method: POST
              headers:
                Authorization: "Bearer ${env:TICKET_API_KEY}"
        max_iterations: 8

      - id: api_developer
        type: react
        model:
          provider: openai
          model: gpt-4o
          api_key: "${env:OPENAI_API_KEY}"
          temperature: 0.3
        system_prompt: |
          You are an API developer assistant. Help with API integration,
          code examples, SDK usage, and webhook configuration.
          Always provide working code snippets in the user's language.
          Search the API reference for accurate endpoint details.
        tools:
          - name: search_api
            type: rag-query
            description: "Search API documentation and code examples"
            parameters:
              type: object
              properties:
                query:
                  type: string
                top_k:
                  type: integer
                  default: 8
            config:
              store: pgvector
              connection: "${env:DATABASE_URL}"
              collection: api_docs
              retriever: hybrid
              alpha: 0.8
        max_iterations: 6

      - id: account_manager
        type: react
        model:
          provider: anthropic
          model: claude-sonnet-4-20250514
          api_key: "${env:ANTHROPIC_API_KEY}"
          temperature: 0.3
        system_prompt: |
          You are an account manager. Help with billing questions,
          subscription changes, team management, and account settings.
          Search policies for accurate information. For account changes,
          gather the required information and guide the user through
          the self-service portal.
        tools:
          - name: search_policies
            type: rag-query
            description: "Search billing and account policies"
            parameters:
              type: object
              properties:
                query:
                  type: string
            config:
              store: pgvector
              connection: "${env:DATABASE_URL}"
              collection: account_policies
              retriever: simple
          - name: lookup_account
            type: connector
            description: "Look up account details"
            parameters:
              type: object
              properties:
                account_id:
                  type: string
            config:
              endpoint: "https://api.internal.example.com/accounts"
              method: GET
              headers:
                Authorization: "Bearer ${env:INTERNAL_API_KEY}"
        max_iterations: 5

10.2 Parallel Analysis Copilot

For copilots that need multi-perspective analysis:

      - agent:
          type: sequential
          model:
            provider: anthropic
            model: claude-sonnet-4-20250514
            api_key: "${env:ANTHROPIC_API_KEY}"
          system_prompt: "Coordinate analysis and synthesis."
          sub_agents:
            # Phase 1: Parallel analysis from 3 perspectives
            - id: parallel-analysis
              type: parallel
              model:
                provider: anthropic
                model: claude-sonnet-4-20250514
                api_key: "${env:ANTHROPIC_API_KEY}"
              system_prompt: "Analyze from multiple perspectives."
              sub_agents:
                - id: technical-view
                  type: react
                  model:
                    provider: openai
                    model: gpt-4o
                    api_key: "${env:OPENAI_API_KEY}"
                    temperature: 0.2
                  system_prompt: "Analyze from a technical feasibility perspective."
                  tools:
                    - name: search
                      type: rag-query
                      description: "Search technical docs"
                      parameters:
                        type: object
                        properties:
                          query: { type: string }
                      config:
                        store: pgvector
                        connection: "${env:DATABASE_URL}"
                        collection: technical_docs
                        retriever: hybrid
                        alpha: 0.7

                - id: business-view
                  type: react
                  model:
                    provider: anthropic
                    model: claude-sonnet-4-20250514
                    api_key: "${env:ANTHROPIC_API_KEY}"
                    temperature: 0.4
                  system_prompt: "Analyze from a business impact perspective."
                  tools:
                    - name: search
                      type: rag-query
                      description: "Search business docs"
                      parameters:
                        type: object
                        properties:
                          query: { type: string }
                      config:
                        store: pgvector
                        connection: "${env:DATABASE_URL}"
                        collection: business_docs
                        retriever: hybrid
                        alpha: 0.6

                - id: risk-view
                  type: react
                  model:
                    provider: anthropic
                    model: claude-sonnet-4-20250514
                    api_key: "${env:ANTHROPIC_API_KEY}"
                    temperature: 0.1
                  system_prompt: "Analyze risks, security concerns, and compliance issues."
                  tools:
                    - name: search
                      type: rag-query
                      description: "Search compliance docs"
                      parameters:
                        type: object
                        properties:
                          query: { type: string }
                      config:
                        store: pgvector
                        connection: "${env:DATABASE_URL}"
                        collection: compliance_docs
                        retriever: simple

            # Phase 2: Synthesize all perspectives
            - id: synthesizer
              type: react
              model:
                provider: anthropic
                model: claude-sonnet-4-20250514
                api_key: "${env:ANTHROPIC_API_KEY}"
                temperature: 0.5
                max_tokens: 3000
              system_prompt: |
                You receive three independent analyses (technical, business, risk).
                Synthesize them into a unified recommendation:
                1. Executive Summary (3 sentences)
                2. Key Findings (from each perspective)
                3. Points of Agreement
                4. Points of Tension
                5. Recommendation with Confidence Level
              max_iterations: 2

11. Step 9 — Security and Authentication

Protect the copilot with authentication, rate limiting, and tenant isolation.

11.1 JWT Authentication

workflows:
  - id: copilot-chat
    trigger:
      uri: agui://0.0.0.0:4100/api/chat?name=copilot&corsOrigin=*
      security:
        - type: jwt
          jwks_url: "${env:JWKS_URL}"
          issuer: "https://auth.example.com"
          audience: "copilot-api"
    steps:
      # Rate limit per user
      - throttle:
          rate: 30
          per: minute
          key:
            starlang: 'headers["auth.subject"]'

      - agent:
          # ... agent config ...

After JWT validation, all claims become headers: - auth.subject — User ID - auth.email — User email (if present) - auth.role — User role - auth.<any> — Any custom claim

11.2 API Key Authentication

    trigger:
      uri: http-server://0.0.0.0:8080/api/chat
      security:
        - type: apikey
          header: "X-API-Key"
          keys:
            - "${env:API_KEY_1}"
            - "${env:API_KEY_2}"
            - "${env:API_KEY_3}"

11.3 OAuth2 Token Introspection

    trigger:
      uri: http-server://0.0.0.0:8080/api/chat
      security:
        - type: oauth2
          token_url: "https://auth.example.com/token/introspect"
          client_id: "copilot-service"
          client_secret: "${env:OAUTH2_CLIENT_SECRET}"
          scopes:
            - "copilot:read"
            - "copilot:write"

11.4 Multi-Tenant Copilot

Isolate knowledge and memory per tenant:

workflows:
  - id: tenant-copilot
    trigger:
      uri: agui://0.0.0.0:4100/api/chat?name=copilot&corsOrigin=*
      security:
        - type: jwt
          jwks_url: "${env:JWKS_URL}"
    steps:
      - throttle:
          rate: 60
          per: minute
          key:
            starlang: 'headers["auth.tenant_id"]'

      - agent:
          type: react
          model:
            provider: anthropic
            model: claude-sonnet-4-20250514
            api_key: "${env:ANTHROPIC_API_KEY}"
            temperature: 0.4
          system_prompt: |
            You are a copilot. Only use information from this tenant's
            knowledge base. Never reference other tenants' data.
          memory:
            enabled: true
            type: sql-long-term
            dsn: "${env:DATABASE_URL}"
            session_id_header: "X-Session-ID"
          tools:
            - name: search
              type: rag-query
              description: "Search this tenant's knowledge base"
              parameters:
                type: object
                properties:
                  query:
                    type: string
                  top_k:
                    type: integer
                    default: 5
              config:
                store: pgvector
                connection: "${env:DATABASE_URL}"
                # Dynamic collection per tenant
                collection:
                  starlang: '"tenant_" ++ headers["auth.tenant_id"]'
                retriever: hybrid
                alpha: 0.7
          max_iterations: 6

helix:
  tenant:
    enabled: true
    header: "auth.tenant_id"
    required: true

11.5 TLS / HTTPS

workflows:
  - id: copilot-secure
    trigger:
      uri: http-server://0.0.0.0:8443/api/chat?tls=true&tlsCert=/etc/helix/tls/server.crt&tlsKey=/etc/helix/tls/server.key&tlsMinVersion=1.3

For mutual TLS (client certificate verification):

?tls=true&tlsCert=server.crt&tlsKey=server.key&tlsCA=ca.crt


12. Step 10 — Multi-Protocol Exposure

Expose the copilot through all protocols simultaneously — chat frontends, Claude Desktop, other agents, and REST API.

agents:
  # ── Core logic (shared by all protocols) ──
  - id: copilot-core
    type: supervisor
    trigger: direct://copilot-core
    model:
      provider: anthropic
      model: claude-sonnet-4-20250514
      api_key: "${env:ANTHROPIC_API_KEY}"
      temperature: 0.3
    system_prompt: |
      You are a helpful copilot. Route to the appropriate specialist.
    memory:
      enabled: true
      type: composite
      session_id_header: "X-Session-ID"
      backends:
        - type: sliding-window
          window_size: 25
        - type: vector
          top_k: 5
          embed:
            provider: openai
            model: text-embedding-3-small
            api_key: "${env:OPENAI_API_KEY}"
        - type: sql-long-term
          dsn: "${env:DATABASE_URL}"
          session_id_header: "X-Session-ID"
    sub_agents:
      - id: general
        type: react
        model:
          provider: anthropic
          model: claude-sonnet-4-20250514
          api_key: "${env:ANTHROPIC_API_KEY}"
        system_prompt: "Answer general questions using the knowledge base."
        tools:
          - name: search
            type: rag-query
            description: "Search knowledge base"
            parameters:
              type: object
              properties:
                query: { type: string }
            config:
              store: pgvector
              connection: "${env:DATABASE_URL}"
              collection: copilot_knowledge
              retriever: hybrid
              alpha: 0.7
        max_iterations: 6

      - id: technical
        type: react
        model:
          provider: openai
          model: gpt-4o
          api_key: "${env:OPENAI_API_KEY}"
        system_prompt: "Help with technical issues and troubleshooting."
        tools:
          - name: search_docs
            type: rag-query
            description: "Search technical docs"
            parameters:
              type: object
              properties:
                query: { type: string }
            config:
              store: pgvector
              connection: "${env:DATABASE_URL}"
              collection: technical_docs
              retriever: hybrid
              alpha: 0.7
          - name: search_tickets
            type: rag-query
            description: "Search past support tickets"
            parameters:
              type: object
              properties:
                query: { type: string }
            config:
              store: pgvector
              connection: "${env:DATABASE_URL}"
              collection: support_tickets
              retriever: hybrid
              alpha: 0.5
        max_iterations: 8

workflows:
  # ── AG-UI: Streaming chat for CopilotKit frontends ──
  - id: copilot-agui
    trigger:
      uri: agui://0.0.0.0:4100/api/chat?name=copilot&corsOrigin=*
    steps:
      - target: direct://copilot-core

  # ── A2UI: Rich declarative UI surfaces ──
  - id: copilot-a2ui
    trigger:
      uri: a2ui://0.0.0.0:4200/api/surface?name=copilot-ui&corsOrigin=*
    steps:
      - target: direct://copilot-core

  # ── A2A: Agent-to-agent (other AI agents call this copilot) ──
  - id: copilot-a2a
    trigger:
      uri: a2a-server://0.0.0.0:9000?name=company-copilot&description=AI+copilot+for+company+knowledge&version=1.0.0
    steps:
      - target: direct://copilot-core

  # ── REST: Traditional HTTP API for scripts and mobile apps ──
  - id: copilot-rest
    trigger:
      uri: http-server://0.0.0.0:8080/api/chat
      security:
        - type: jwt
          jwks_url: "${env:JWKS_URL}"
    steps:
      - target: direct://copilot-core

  # ── MCP: Expose copilot as tools for Claude Desktop ──
  # (Configured via helix.mcp.server, not as a workflow)

helix:
  mcp:
    server:
      enabled: true
      transport: http
      addr: "0.0.0.0:3000"
      name: "company-copilot"
      version: "1.0.0"
      workflows:
        - copilot-core
      tools:
        copilot-core:
          description: "Ask the company AI copilot any question"
          input_schema: '{"type":"object","properties":{"query":{"type":"string"}},"required":["query"]}'

  a2a:
    servers:
      - enabled: true
        addr: "0.0.0.0:9000"
        name: "company-copilot"
        description: "AI copilot with access to company knowledge base, support history, and account management"
        version: "1.0.0"

  agui:
    servers:
      - enabled: true
        addr: "0.0.0.0:4100"
        path: "/api/chat"
        name: "copilot"

  a2ui:
    servers:
      - enabled: true
        addr: "0.0.0.0:4200"
        path: "/api/surface"
        name: "copilot-ui"

13. Step 11 — Observability and Quality Monitoring

Monitor copilot performance, response quality, and usage patterns.

13.1 RAG Quality Evaluation

Evaluate every RAG-augmented response:

  # Add after the agent step in copilot-core
  - id: copilot-core
    trigger:
      uri: direct://copilot-core
    steps:
      - agent:
          # ... supervisor config ...

      # Evaluate response quality
      - rag-eval:
          metrics:
            - faithfulness
            - answer_relevancy
          model:
            provider: openai
            model: gpt-4o-mini
            api_key: "${env:OPENAI_API_KEY}"

      # Non-blocking: send metrics to monitoring pipeline
      - wiretap: seda://copilot-metrics

      # Tag response with quality score
      - set-header:
          name: X-Copilot-Quality
          starlang: |
            faith = float(properties.get("rag_faithfulness", "1"))
            if faith >= 0.7:
              "high"
            elif faith >= 0.4:
              "medium"
            else:
              "low"

13.2 Metrics Collection and Alerting

workflows:
  # Metrics processor (non-blocking via SEDA)
  - id: copilot-metrics-processor
    trigger:
      uri: seda://copilot-metrics?concurrency=4
    steps:
      # Log for Prometheus scraping
      - target: log://copilot-quality?level=info

      # Alert on low quality
      - choice:
          when:
            - starlang: |
                faith = float(properties.get("rag_faithfulness", "1"))
                faith < 0.3
              steps:
                - set-body:
                    starlang: |
                      write({
                        "channel": "copilot-alerts",
                        "text": "Low quality response detected (faithfulness: " ++
                                properties.get("rag_faithfulness", "N/A") ++ ")"
                      }, "application/json")
                - target: slack://alerts?webhook=${env:SLACK_WEBHOOK}

  # Daily quality digest
  - id: copilot-daily-digest
    trigger:
      uri: cron://daily?schedule=0 9 * * 1-5
    steps:
      - agent:
          type: react
          model:
            provider: openai
            model: gpt-4o-mini
            api_key: "${env:OPENAI_API_KEY}"
            temperature: 0.1
          system_prompt: |
            Generate a daily copilot quality report:
            1. Total queries (24h)
            2. Average quality scores
            3. Quality trend
            4. Top failed queries
            5. Improvement recommendations
          tools:
            - name: query_metrics
              type: connector
              description: "Query Prometheus metrics"
              parameters:
                type: object
                properties:
                  query: { type: string }
              config:
                endpoint: "http://prometheus:9090/api/v1/query"
                method: GET
          max_iterations: 3
      - target: slack://copilot-ops?channel=daily-report&webhook=${env:SLACK_WEBHOOK}

13.3 Observability Configuration

helix:
  metrics:
    enabled: true
    addr: "0.0.0.0:9090"
    path: "/metrics"

  tracing:
    enabled: true
    exporter: otlp
    endpoint: "http://jaeger:4318"
    sample_rate: 0.1

  audit:
    enabled: true
    buffer_size: 10000

  logging:
    level: info
    format: json

14. Step 12 — Production Deployment

Final production configuration with graceful shutdown, clustering, and resilience.

helix:
  shutdown:
    timeout: 30s
    drain_timeout: 15s

  cluster:
    enabled: true
    backend: redis
    redis_addr: "${env:REDIS_URL}"
    node_name: "${env:HOSTNAME}"

  tenant:
    enabled: true
    header: "auth.tenant_id"
    required: true

  audit:
    enabled: true
    buffer_size: 10000

  logging:
    level: info
    format: json
    components:
      agent: debug
      rag: info

Dockerfile

FROM golang:1.25-alpine AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o helix ./cmd/helix

FROM alpine:3.21
RUN apk add --no-cache ca-certificates
COPY --from=builder /app/helix /usr/local/bin/helix
COPY copilot.yaml /etc/helix/copilot.yaml
COPY knowledge-base/ /data/knowledge-base/
EXPOSE 4100 4200 3000 8080 9000 9090
ENTRYPOINT ["helix", "run", "/etc/helix/copilot.yaml"]

Docker Compose

version: "3.9"
services:
  copilot:
    build: .
    ports:
      - "4100:4100"   # AG-UI (chat frontend)
      - "4200:4200"   # A2UI (rich UI)
      - "3000:3000"   # MCP (Claude Desktop)
      - "8080:8080"   # REST API
      - "9000:9000"   # A2A (agent-to-agent)
      - "9090:9090"   # Prometheus metrics
    environment:
      - ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
      - OPENAI_API_KEY=${OPENAI_API_KEY}
      - DATABASE_URL=postgres://helix:helix@postgres:5432/copilot
      - REDIS_URL=redis:6379
      - JWKS_URL=https://auth.example.com/.well-known/jwks.json
    depends_on:
      - postgres
      - redis

  postgres:
    image: pgvector/pgvector:pg17
    environment:
      POSTGRES_USER: helix
      POSTGRES_PASSWORD: helix
      POSTGRES_DB: copilot
    volumes:
      - pgdata:/var/lib/postgresql/data
    ports:
      - "5432:5432"

  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"

  prometheus:
    image: prom/prometheus
    volumes:
      - ./deploy/prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
    ports:
      - "9091:9090"

  grafana:
    image: grafana/grafana
    volumes:
      - ./deploy/grafana/dashboards:/var/lib/grafana/dashboards
    ports:
      - "3001:3000"
    environment:
      - GF_SECURITY_ADMIN_PASSWORD=admin

volumes:
  pgdata:

15. Complete Copilot — Full YAML Reference

A single-file copilot configuration combining all capabilities:

# ================================================================
# Complete AI Copilot Configuration
# ================================================================
# Features:
#   - AG-UI streaming chat (CopilotKit compatible)
#   - A2UI rich declarative UIs
#   - MCP tool server (Claude Desktop, Cursor)
#   - A2A agent-to-agent protocol
#   - REST API endpoint
#   - RAG knowledge base with nightly + incremental ingestion
#   - Composite memory (sliding window + vector + SQL persistent)
#   - Multi-agent supervisor with 4 specialists
#   - JWT authentication + rate limiting
#   - Quality evaluation + Slack alerting
#   - Prometheus metrics + audit logging
# ================================================================

workflows:
  # ── PROTOCOL ENDPOINTS ──────────────────────────────────────

  # AG-UI: Streaming chat for frontends
  - id: copilot-agui
    trigger:
      uri: agui://0.0.0.0:4100/api/chat?name=copilot&corsOrigin=*
    steps:
      - target: direct://copilot-core

  # A2UI: Rich UI surfaces
  - id: copilot-a2ui
    trigger:
      uri: a2ui://0.0.0.0:4200/api/surface?name=copilot-ui&corsOrigin=*
    steps:
      - target: direct://copilot-core

  # A2A: Other agents can call this copilot
  - id: copilot-a2a
    trigger:
      uri: a2a-server://0.0.0.0:9000?name=company-copilot&version=1.0.0
    steps:
      - target: direct://copilot-core

  # REST: HTTP API for scripts, mobile, webhooks
  - id: copilot-rest
    trigger:
      uri: http-server://0.0.0.0:8080/api/chat
      security:
        - type: jwt
          jwks_url: "${env:JWKS_URL}"
          issuer: "https://auth.example.com"
          audience: "copilot-api"
    steps:
      - throttle:
          rate: 30
          per: minute
          key:
            starlang: 'headers["auth.subject"]'
      - target: direct://copilot-core

  # ── CORE COPILOT LOGIC ──────────────────────────────────────

  - id: copilot-core
    trigger:
      uri: direct://copilot-core
    steps:
      - agent:
          type: supervisor
          model:
            provider: anthropic
            model: claude-sonnet-4-20250514
            api_key: "${env:ANTHROPIC_API_KEY}"
            temperature: 0.3
          system_prompt: |
            You are the copilot supervisor for [Company Name].
            Route questions to the appropriate specialist:

            - general_assistant: General questions, product info, how-to guides
            - technical_support: Bugs, errors, configuration, troubleshooting
            - api_developer: API usage, code examples, SDK integration
            - account_manager: Billing, subscriptions, account settings

            For cross-domain questions, start with the primary domain.
          memory:
            enabled: true
            type: composite
            session_id_header: "X-Session-ID"
            backends:
              - type: sliding-window
                window_size: 25
              - type: vector
                top_k: 5
                embed:
                  provider: openai
                  model: text-embedding-3-small
                  api_key: "${env:OPENAI_API_KEY}"
              - type: sql-long-term
                dsn: "${env:DATABASE_URL}"
                session_id_header: "X-Session-ID"

          sub_agents:
            - id: general_assistant
              type: react
              model:
                provider: anthropic
                model: claude-sonnet-4-20250514
                api_key: "${env:ANTHROPIC_API_KEY}"
                temperature: 0.4
                max_tokens: 2048
              system_prompt: |
                You are a helpful assistant. Search the knowledge base to answer
                questions. Cite sources. If unsure, say so honestly.
              tools:
                - name: search_knowledge
                  type: rag-query
                  description: "Search the company knowledge base"
                  parameters:
                    type: object
                    properties:
                      query:
                        type: string
                      top_k:
                        type: integer
                        default: 5
                    required: [query]
                  config:
                    store: pgvector
                    connection: "${env:DATABASE_URL}"
                    collection: copilot_knowledge
                    retriever: hybrid
                    alpha: 0.7
                - name: search_diverse
                  type: rag-query
                  description: "Search for diverse perspectives"
                  parameters:
                    type: object
                    properties:
                      query:
                        type: string
                  config:
                    store: pgvector
                    connection: "${env:DATABASE_URL}"
                    collection: copilot_knowledge
                    retriever: mmr
                    lambda: 0.3
                    fetch_k: 25
              max_iterations: 6

            - id: technical_support
              type: react
              model:
                provider: openai
                model: gpt-4o
                api_key: "${env:OPENAI_API_KEY}"
                temperature: 0.2
              system_prompt: |
                You are technical support. Diagnose issues methodically.
                Search docs and past tickets. Provide step-by-step solutions.
              tools:
                - name: search_docs
                  type: rag-query
                  description: "Search technical documentation"
                  parameters:
                    type: object
                    properties:
                      query: { type: string }
                      top_k: { type: integer, default: 5 }
                  config:
                    store: pgvector
                    connection: "${env:DATABASE_URL}"
                    collection: technical_docs
                    retriever: hybrid
                    alpha: 0.7
                - name: search_tickets
                  type: rag-query
                  description: "Search past support tickets"
                  parameters:
                    type: object
                    properties:
                      query: { type: string }
                  config:
                    store: pgvector
                    connection: "${env:DATABASE_URL}"
                    collection: support_tickets
                    retriever: hybrid
                    alpha: 0.5
                - name: create_ticket
                  type: connector
                  description: "Escalate by creating a support ticket"
                  parameters:
                    type: object
                    properties:
                      title: { type: string }
                      description: { type: string }
                      priority: { type: string, enum: [low, medium, high, urgent] }
                    required: [title, description]
                  config:
                    endpoint: "https://api.ticketing.example.com/tickets"
                    method: POST
                    headers:
                      Authorization: "Bearer ${env:TICKET_API_KEY}"
                - name: github_tools
                  type: mcp
                  description: "Search code and manage issues on GitHub"
                  mcp_server:
                    command: "npx"
                    args: ["@modelcontextprotocol/server-github"]
                    transport: stdio
                    tools: [search_code, get_file_contents, list_issues, create_issue]
              max_iterations: 8

            - id: api_developer
              type: react
              model:
                provider: openai
                model: gpt-4o
                api_key: "${env:OPENAI_API_KEY}"
                temperature: 0.3
              system_prompt: |
                You are an API developer assistant. Provide working code
                snippets, accurate endpoint details, and SDK integration guides.
              tools:
                - name: search_api
                  type: rag-query
                  description: "Search API documentation and examples"
                  parameters:
                    type: object
                    properties:
                      query: { type: string }
                      top_k: { type: integer, default: 8 }
                  config:
                    store: pgvector
                    connection: "${env:DATABASE_URL}"
                    collection: api_docs
                    retriever: hybrid
                    alpha: 0.8
              max_iterations: 6

            - id: account_manager
              type: react
              model:
                provider: anthropic
                model: claude-sonnet-4-20250514
                api_key: "${env:ANTHROPIC_API_KEY}"
                temperature: 0.3
              system_prompt: |
                You are an account manager. Help with billing, subscriptions,
                and account settings. Search policies for accurate info.
              tools:
                - name: search_policies
                  type: rag-query
                  description: "Search account and billing policies"
                  parameters:
                    type: object
                    properties:
                      query: { type: string }
                  config:
                    store: pgvector
                    connection: "${env:DATABASE_URL}"
                    collection: account_policies
                    retriever: simple
                - name: lookup_account
                  type: connector
                  description: "Look up account details"
                  parameters:
                    type: object
                    properties:
                      account_id: { type: string }
                  config:
                    endpoint: "https://api.internal.example.com/accounts"
                    method: GET
                    headers:
                      Authorization: "Bearer ${env:INTERNAL_API_KEY}"
              max_iterations: 5

      # Quality evaluation
      - rag-eval:
          metrics:
            - faithfulness
            - answer_relevancy
          model:
            provider: openai
            model: gpt-4o-mini
            api_key: "${env:OPENAI_API_KEY}"

      # Non-blocking metrics
      - wiretap: seda://copilot-metrics

  # ── RAG INGESTION ────────────────────────────────────────────

  # Nightly full reindex
  - id: copilot-ingest-full
    trigger:
      uri: cron://nightly?schedule=0 2 * * *
    steps:
      - rag-ingest:
          reader: directory
          path: ./knowledge-base
          recursive: true
          extensions: [".md", ".pdf", ".html", ".txt", ".docx"]
      - rag-chunk:
          strategy: semantic
          threshold: 0.45
          chunk_size: 1000
          overlap: 150
      - rag-embed:
          provider: openai
          model: text-embedding-3-small
          api_key: "${env:OPENAI_API_KEY}"
      - rag-store:
          store: pgvector
          connection: "${env:DATABASE_URL}"
          collection: copilot_knowledge
          dimensions: 1536
      - rag-extract:
          extractors: [title, keywords, summary]
          model:
            provider: openai
            model: gpt-4o-mini
            api_key: "${env:OPENAI_API_KEY}"
      - target: log://ingestion?level=info

  # Hourly incremental updates
  - id: copilot-ingest-incremental
    trigger:
      uri: cron://hourly?schedule=0 * * * *
    steps:
      - rag-ingest:
          reader: directory
          path: ./knowledge-base
          recursive: true
      - filter:
          starlang: |
            import "time"
            modified = headers["HelixFileLastModified"]
            modified > time.now() - time.hour
      - rag-chunk:
          strategy: semantic
          threshold: 0.45
          chunk_size: 1000
          overlap: 150
      - rag-embed:
          provider: openai
          model: text-embedding-3-small
          api_key: "${env:OPENAI_API_KEY}"
      - rag-store:
          store: pgvector
          connection: "${env:DATABASE_URL}"
          collection: copilot_knowledge

  # ── MONITORING ───────────────────────────────────────────────

  - id: copilot-metrics-processor
    trigger:
      uri: seda://copilot-metrics?concurrency=4
    steps:
      - target: log://copilot-quality?level=info
      - choice:
          when:
            - starlang: |
                faith = float(properties.get("rag_faithfulness", "1"))
                faith < 0.3
              steps:
                - set-body:
                    starlang: |
                      write({
                        "text": "Low quality copilot response (faithfulness: " ++
                                properties.get("rag_faithfulness", "N/A") ++ ")"
                      }, "application/json")
                - target: slack://alerts?webhook=${env:SLACK_WEBHOOK}

  - id: copilot-daily-digest
    trigger:
      uri: cron://daily?schedule=0 9 * * 1-5
    steps:
      - agent:
          type: react
          model:
            provider: openai
            model: gpt-4o-mini
            api_key: "${env:OPENAI_API_KEY}"
            temperature: 0.1
          system_prompt: "Generate a daily copilot quality report."
          tools:
            - name: query_metrics
              type: connector
              description: "Query Prometheus"
              parameters:
                type: object
                properties:
                  query: { type: string }
              config:
                endpoint: "http://prometheus:9090/api/v1/query"
                method: GET
          max_iterations: 3
      - target: slack://copilot-ops?webhook=${env:SLACK_WEBHOOK}

# ── GLOBAL CONFIGURATION ──────────────────────────────────────

helix:
  mcp:
    server:
      enabled: true
      transport: http
      addr: "0.0.0.0:3000"
      name: "company-copilot"
      version: "1.0.0"
      workflows: [copilot-core]
      tools:
        copilot-core:
          description: "Ask the AI copilot any question"
          input_schema: '{"type":"object","properties":{"query":{"type":"string"}},"required":["query"]}'

  a2a:
    servers:
      - enabled: true
        addr: "0.0.0.0:9000"
        name: "company-copilot"
        description: "AI copilot with company knowledge, support, and account management"
        version: "1.0.0"

  agui:
    servers:
      - enabled: true
        addr: "0.0.0.0:4100"
        path: "/api/chat"
        name: "copilot"

  a2ui:
    servers:
      - enabled: true
        addr: "0.0.0.0:4200"
        path: "/api/surface"
        name: "copilot-ui"

  shutdown:
    timeout: 30s
    drain_timeout: 15s

  audit:
    enabled: true
    buffer_size: 10000

  logging:
    level: info
    format: json

  metrics:
    enabled: true
    addr: "0.0.0.0:9090"
    path: "/metrics"

16. Copilot Patterns

16.1 Customer Support Copilot

Feature Configuration
Agent type Supervisor with 4 specialists (product, technical, billing, escalation)
RAG collections Product docs, technical docs, support tickets, FAQs
Memory Composite (sliding window + SQL persistent)
Tools RAG search, ticket creation, account lookup
Protocols AG-UI (chat widget), REST API (mobile), MCP (internal)

16.2 Developer Copilot

Feature Configuration
Agent type ReAct with code-focused tools
RAG collections API docs (code chunking), examples, changelogs
Memory Composite (sliding window + vector semantic)
Tools RAG search, GitHub MCP (code search, issues), code execution
Protocols AG-UI (IDE panel), MCP (Cursor/VS Code)

16.3 Enterprise Knowledge Copilot

Feature Configuration
Agent type Supervisor with domain experts
RAG collections Per-department knowledge bases (engineering, legal, HR, finance)
Memory Composite (sliding window + vector + SQL) with per-tenant isolation
Tools RAG search (4 collections), document upload, Slack notifications
Security JWT + multi-tenant + rate limiting
Protocols AG-UI, A2A (other agents query this), MCP, REST

16.4 Research Copilot

Feature Configuration
Agent type Plan-Execute or Deep (for complex research)
RAG collections Research corpus with semantic chunking
Memory Composite (sliding window + vector for cross-session recall)
Tools RAG search (hybrid + MMR + HyDE), web search MCP
Quality RAG evaluation on every response, self-reflective loop
Protocols AG-UI (research dashboard), REST API

16.5 Internal Operations Copilot

Feature Configuration
Agent type Supervisor with ops specialists
RAG collections Runbooks, incident history, architecture docs
Memory SQL persistent (audit trail requirement)
Tools RAG search, MCP (filesystem, database, Kubernetes), HTTP (PagerDuty, Jira)
Security JWT + mTLS + audit logging
Protocols AG-UI (ops dashboard), A2A (incident bots call this), MCP

17. Frontend Integration Guide

17.1 CopilotKit (React)

npm install @copilotkit/react-core @copilotkit/react-ui
import { CopilotKit } from "@copilotkit/react-core";
import { CopilotChat } from "@copilotkit/react-ui";
import "@copilotkit/react-ui/styles.css";

function App() {
  return (
    <CopilotKit
      runtimeUrl="http://localhost:4100/api/chat"
      headers={{
        "X-Session-ID": getSessionId(),
        "Authorization": `Bearer ${getToken()}`
      }}
    >
      <YourApp />
      <CopilotChat
        labels={{
          title: "AI Copilot",
          initial: "Hi! How can I help you today?"
        }}
      />
    </CopilotKit>
  );
}

17.2 Custom SSE Client (Vanilla JS)

async function sendMessage(message, sessionId) {
  const response = await fetch("http://localhost:4100/api/chat", {
    method: "POST",
    headers: {
      "Content-Type": "application/json",
      "X-Session-ID": sessionId,
    },
    body: JSON.stringify({
      threadId: sessionId,
      runId: crypto.randomUUID(),
      messages: [{ role: "user", content: message }],
    }),
  });

  const reader = response.body.getReader();
  const decoder = new TextDecoder();
  let buffer = "";

  while (true) {
    const { done, value } = await reader.read();
    if (done) break;

    buffer += decoder.decode(value, { stream: true });
    const lines = buffer.split("\n");
    buffer = lines.pop();

    for (const line of lines) {
      if (line.startsWith("data: ")) {
        const event = JSON.parse(line.slice(6));
        switch (event.type) {
          case "TEXT_MESSAGE_CONTENT":
            appendToChat(event.delta);
            break;
          case "RUN_FINISHED":
            finishMessage();
            break;
          case "RUN_ERROR":
            showError(event.message);
            break;
        }
      }
    }
  }
}

17.3 A2UI Surface Client

function connectSurface(message) {
  const url = `http://localhost:4200/api/surface?message=${encodeURIComponent(message)}&surface=main`;
  const eventSource = new EventSource(url);

  eventSource.onmessage = (event) => {
    const msg = JSON.parse(event.data);

    if (msg.beginRendering) {
      initSurface(msg.beginRendering.surfaceId);
    }
    if (msg.updateComponents) {
      renderComponents(msg.updateComponents.components);
    }
    if (msg.dataModelUpdate) {
      updateData(msg.dataModelUpdate.updates);
    }
  };

  eventSource.onerror = () => eventSource.close();
}

// Send user action back
async function sendAction(componentId, data) {
  await fetch("http://localhost:4200/api/surface", {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      event: {
        surfaceId: "main",
        componentId,
        type: "action",
        data,
      },
    }),
  });
}

17.4 Claude Desktop (MCP)

Add to claude_desktop_config.json:

{
  "mcpServers": {
    "company-copilot": {
      "url": "http://localhost:3000"
    }
  }
}

Claude Desktop will automatically discover and list the copilot as an available tool.

17.5 Python Client (A2A)

import requests

def ask_copilot(message: str) -> str:
    """Call the copilot via A2A protocol."""
    response = requests.post(
        "http://localhost:9000/invoke",
        json={
            "jsonrpc": "2.0",
            "method": "message/send",
            "params": {
                "message": {
                    "role": "user",
                    "parts": [{"text": message}]
                }
            },
            "id": "1"
        }
    )
    result = response.json()
    # Extract text from response
    return result["result"]["parts"][0]["text"]

This guide covers building a complete AI copilot from scratch to production deployment. For more patterns, see the Use Cases & Examples. For component reference, see Components. For agent internals, see AI Agents Guide. For RAG details, see RAG Guide.