# Messaging Channels — direct Meta vs CRM (GHL / Kommo)

> An agent can answer messages from **two different places**, and the difference is invisible
> until you look for it. This doc is how you tell whether an agent is a **free Meta agent**
> (connected straight to Instagram/WhatsApp in Ninjo) or a **CRM-served agent** (it only
> answers what a CRM like GoHighLevel or Kommo **relays** into Ninjo). Pairs with
> `knowledge/mcp-tool-reference.md` (§Reads) and `knowledge/platform-features.md`.

## The two sources of a channel

| Source | What it means | Where it lives |
|---|---|---|
| `"direct"` | A Meta sub-account (Instagram / WhatsApp) connected **directly in Ninjo**. The agent owns that inbox. | `connected_sub_account_meta` linked to the agent (`_AgentToConnectedSubAccountMeta`). |
| `"crm"` | A **CRM sync connection** (GHL / Kommo / HubSpot / Airtable). The agent is **not** on IG directly — it answers the messages the CRM forwards in through that channel. | `sync_connections` row whose `agent_id` points at the agent. |

Why it matters: if a user asks "is this agent free?" or "why isn't it replying on Instagram?",
a `source: "crm"` channel is the answer — the agent is **dedicated to the CRM channel**, not
sitting idle. Reading only the Meta accounts (`list_connected_accounts`) hides this entirely.

## Reading channels — `list_agent_channels`

One unified view of everything an agent answers:

```text
list_agent_channels(agent_id) → { channels, count }
```

Each channel carries:

- `source` — `"direct"` | `"crm"` (the whole point).
- `channel_type` — the Meta `account_type` (`INSTAGRAM`, `WHATSAPP`) for direct, or the CRM
  `provider` (`GHL`, `KOMMO`, `HUBSPOT`, `AIRTABLE`) for crm.
- `connected` — the single "is this channel live" flag. Direct: the Meta token is valid.
  CRM: the connection is **enabled AND not disconnected**. A `connected: false` CRM channel is
  wired but currently dead (disabled or `disconnected_at` set).
- `id`, `name`, timestamps, plus `meta_id` (direct) or `connected_account_id` +
  `disconnected_at` (crm).

Metadata only — no access tokens or webhook secrets are ever returned.

### How to answer the common questions

- **"Is this agent free / where does it answer?"** → `list_agent_channels`. Any `source:"crm"`
  channel ⇒ it serves that CRM; only `source:"direct"` ⇒ a normal Meta agent.
- **"Why no replies on Instagram?"** → if the agent has only `source:"crm"` channels, it was
  never on IG directly. If it has a `direct` channel with `connected:false`, the Meta token is
  invalid (reconnect in Ninjo).
- **"Is the GHL/Kommo link alive?"** → find the `source:"crm"` channel and read `connected`.

## Routing a CRM channel — `set_agent_crm_channel`

A CRM sync connection routes to a **single** agent (unlike Meta accounts, which are
many-to-many). So:

```text
set_agent_crm_channel(sync_connection_id, agent_id)      # route this CRM channel to that agent
set_agent_crm_channel(sync_connection_id, agent_id=null) # unroute it from any agent
```

- Routing to a new agent **replaces** the previous one (single `agent_id` column) — it is not
  additive. That is the opposite of `set_connected_account`, which adds a Meta link and leaves
  the others intact.
- Both the sync connection and (when routing) the target agent must belong to the influencer;
  the tool rejects cross-tenant ids.
- Discover the `sync_connection_id` with `list_crm_connections` — it lists **all** of the
  influencer's CRM connections, routed or not (`knowledge/property-actions.md` §discovery).
  `list_agent_channels` only shows connections **already routed** to that agent (the `id` of a
  `source:"crm"` channel), so use it to inspect the current assignment, not to find a new one.

## Direct Meta accounts — the other half

To manage direct IG/WhatsApp accounts (not CRM), use the Meta tools instead:
`list_influencer_connected_accounts` (discover), `list_connected_accounts` (per agent),
`set_connected_account` (link/unlink, additive). `list_agent_channels` **shows** both sources
in one place; the write tools are split by source (`set_connected_account` for Meta,
`set_agent_crm_channel` for CRM).
