Served by allternit-api (cloud computer or Desktop) under /api/v1, for the signed-in owner. Everything is owner-scoped: one owner never sees or matches another’s people. The feature needs no env var; with no inbound messages there are no people. Migration V231__people.sql creates people, person_identities, person_link_proposals, person_merges, person_threads and person_facts, and runs with the other runtime migrations.

How inbound messages use it

Every inbound message is resolved before routing (people::sender). The sender’s handle is normalised (E.164 for sms, whatsapp, whatsapp-personal; lower-case for email; team:user for Slack) and matched:
  1. A known (provider, id) is that person.
  2. A phone or email already on another channel links on the spot (source: exact_match).
  3. In a direct conversation an unknown handle makes a new person; in a group it is left unknown.
A direct message lands in the person’s main thread for the bot (channel_thread key person:<id>). person_threads records main and sub threads; at boot and on GET /people the runtime adopts chats that existed before (a direct binding whose inbound log has exactly one sender), parenting their threads under the main thread. A conversation bound to a person who was split or merged away follows the sender on the next message. Replies use people::choose_reply: a channel the bot requests (only if the person has a bound conversation there), else replyPin, else the channel the message arrived on; a bot-started message uses the identity seen last. The turn text starts [<provider> from <name>] and, when the person has notes, ends with (Known about <name>, from every channel: …).

Routes

Person is { id, displayName, nameSource: "auto" | "contact" | "owner", avatar, notes, org, replyPin, identities: [{ id, provider, kind, externalId, label, confidence, source, lastSeenAt }], channels, lastChannel, lastSeenAt, threads: [{ threadId, botId, role }], facts: [{ id, fact, botId, createdAt }] } (newest 50 notes; botId is null for notes the owner typed). Bots write notes with the people_remember tool, see People. GET /gateway/channel-accounts/:id/conversations now also returns personId (and the person’s name and avatar) for each chat, which is how Messages groups by person.