By default every channel is bound to one Qor. Routing rules let you override that per-sender, per-keyword, per-group, per-time-window — without writing any code.

Where rules live

Routing rules are TOML or YAML in /etc/qorven/routing.yml (or the equivalent under ~/.qorven/). The file is hot-reloaded; no restart required.
# /etc/qorven/routing.yml
rules:

  # VIP senders go to the CEO's personal Qor
  - match:
      channel: telegram
      from_username: priya
    qor: ceo-personal

  # Keyword routing
  - match:
      keyword: ["URGENT", "outage", "on-call"]
    qor: oncall
    priority: high

  # Group-based
  - match:
      channel: slack
      group: "#engineering"
    qor: engineering-bot

  # Time windows (after-hours support goes to the night Qor)
  - match:
      channel: whatsapp
      time: "22:00-08:00 IST"
    qor: night-support

  # Default fallback
  - match: all
    qor: prime

Match operators

KeyTypeMatches
channelstringChannel ID (telegram, slack, whatsapp, …)
fromstringSender identity (email, phone, username, user ID)
from_usernamestringProvider-specific username
groupstringGroup name / ID for multi-party channels
keywordstring[]Any of these substrings in the message
regexstringMatch against message content (PCRE)
timestringTime range in operator’s timezone ("22:00-08:00 IST")
schedulestringCron expression for dates/days
languagestringDetected language code
Rules are evaluated top-to-bottom. First match wins. match: all as the final rule is the idiomatic fallback.

Rule actions

Beyond routing to a different Qor, rules can:
- match:
    keyword: ["delete", "drop", "destroy"]
  qor: prime
  require_approval: true         # destructive → human approval
  notify: priya@acme.com         # alert someone

- match:
    channel: webchat
    from: anonymous
  qor: support
  rate_limit: "5/minute"          # anti-abuse
  max_session_length: 20          # cap turns
  fallback_to: "https://acme.com/contact"

Priority Qors

When multiple specialists are viable, priority: high makes the message skip the queue:
- match:
    keyword: ["emergency", "fire", "outage"]
  qor: oncall
  priority: high   # bypasses normal delegation queue

Per-channel defaults

If you don’t want a whole routing.yml, each channel binding has three built-in overrides in the UI:
  1. Primary Qor — who handles this channel
  2. Fallback Qor — if primary is busy or down
  3. Silent mode — don’t reply unless mentioned
Set them in Settings → Channels → (channel) → Routing.

Testing rules

qorven channels test-routing \
  --channel telegram \
  --from priya \
  --message "URGENT server down"
# → matched rule: { match: { keyword: ["URGENT"] } }
# → would route to: oncall
# → priority: high

Where next

Groups vs DMs

How group-scoped routing interacts with memory scopes.

Approvals

When a routed message triggers a destructive action.

Debounce

Batching rapid messages before routing.

Quotas

Per-tenant and per-channel rate limits.