← Documentation index Architecture guide › pairing

Metnos

pairing — connecting users, channels, and devices
A guide to verified identity and instance bindings

Ask Metnos with a request like this example: “Show me how to connect Telegram to the user Lucia.” The Tutor gives the path in the web chat even when the question comes from Telegram.

In Metnos, pairing establishes a verified identity before a request is processed. Identity is never inferred from message text. A logical user, a channel address, a chat session, and an execution device are distinct objects with independent registries and revocation paths.

Contents

  1. The four bindings
  2. Users, roles, and isolation
  3. Pairing Telegram or a browser
  4. Signed channel codes
  5. Active session and conversation transfer
  6. Remote-executor devices
  7. Revocation and lifecycle
  8. Security invariants

1. The four bindings

ObjectWhat it identifiesCurrent source
Logical userThe person who owns a role, preferences, language, and channels.users.db, users table
ChannelA verified address, such as a Telegram chat_id or a paired browser.users.db, user_channels table; Telegram also uses pairings.db
Chat sessionThe device that currently has write access to the user's web conversation.users.db, active_sessions and chat_conversations tables
Remote deviceA machine authorised to run executors for a specified owner.devices.db, devices table

A paired browser is not automatically a remote device. The former provides chat access; the latter receives work from the server and runs it on the machine where the relevant data or applications live. Likewise, transferring a web session does not alter Telegram pairing or device ownership.

2. Users, roles, and isolation

runtime/users.py maintains one host user and any number of guest users. Each record has a technical identifier, a unique name, a role, an optional owner, and an autonomy level. user_channels links that same user to verified telegram, mail, and http channels.

Language and preferences are resolved from the authenticated binding before the turn and applied in a request-local context. A change for one user does not change another user's language or session. Conversations, pending dialogs, and web-chat write authority are also scoped by user and channel.

The two registries use different vocabularies and they are not interchangeable:

In the Telegram daemon, ReadOnly prevents an operational turn from starting. Supervised and Full can enter the runtime; every executor remains subject to its manifest, safety controls, and required approvals. A stored level is not, by itself, proof that a particular action is authorised.

3. Pairing Telegram or a browser

From the web chat, open Settings > System > Users. Create or select the user, then use the pairing control for the required channel. If you are reading these instructions in Telegram, this path is in the Metnos web chat, not in the Telegram application.

Telegram

  1. From the user detail page, issue a token for the Telegram channel.
  2. Transfer the token to the person through a trusted medium.
  3. The person opens the Metnos bot and sends /start <token>.
  4. The daemon consumes the token, binds the chat_id to the user, and confirms the pairing.

The token is random, one-time, and valid for one hour. Consumption uses a SQLite transaction, so two concurrent requests cannot both use the same token. The /start command performs the pairing but does not run an operational request; the next message starts a new turn.

Browsers and other web devices

  1. From the user detail page, issue the HTTP-channel link.
  2. Open that link once in the browser to pair.
  3. Metnos consumes the token, records the binding, and stores a signed, HttpOnly, Secure cookie.

The user cookie lasts at most 90 days, but on every verification the server checks that the HTTP binding still exists. Removing the channel from the user detail page therefore invalidates access even if the browser retains the cookie.

4. Signed channel codes

runtime/pairing.py also provides the technical /pair PAIR.<payload>.<signature> flow. The payload declares the version, identifier, autonomy level, expiry, and issuer; its Ed25519 signature is checked against trusted public keys. By default, a code expires after five minutes and can be consumed only once.

./.venv/bin/python -m runtime.pairing generate <ReadOnly|Supervised|Full> 5m
./.venv/bin/python -m runtime.pairing list
./.venv/bin/python -m runtime.pairing revoke telegram <sender_id>

This flow creates the low-level (channel, sender_id) record. To connect a person who already exists in the user registry, the Settings > System > Users flow with /start is more direct because it preserves the logical identity explicitly.

When bootstrap is enabled, the first message from the default_chat_id can create a Full pairing only while the channel has no pairing records. The --no-bootstrap option instead requires an explicit pairing for the host as well.

5. Active session and conversation transfer

Metnos allows one active write session for each (user, web channel) pair. If you open the chat on one device while another device holds the session, the window offers three choices:

ChoiceEffect
Continue the previous sessionRevokes the old device's write authority, transfers its conversation to the current device, and displays its history.
Make the current session activeRevokes the old device and keeps the current device's local conversation.
CancelChanges no session; the current device remains without write authority.

Resolution is atomic and bound to the authenticated user. The resolution token is one-time, and a user cannot transfer someone else's conversation. When connected, the previous device receives the revocation event and becomes read-only. The conversation belongs to the user, not to the browser.

6. Remote-executor devices

From the web chat, open Settings > System > Devices. The page lists the name, owner, operating system, client version, key fingerprint, last heartbeat, and state. You can install the client on the current PC, generate a link for a different PC, or issue a manual token.

The guided flow is:

  1. The administrator chooses a name and owner and creates a join session.
  2. The target PC opens the link and downloads the Windows or Linux installer.
  3. The client generates an Ed25519 key pair locally; its private key never leaves the device.
  4. POST /agent/register consumes the token and records the public key, fingerprint, owner, and system characteristics.
  5. The server returns its public key; the client pins it and uses it to verify subsequent orders.
  6. The first heartbeat completes the observable installation flow.

The guided join session uses a signed, one-time token that normally lasts 30 minutes; the manual variant issued from the page lasts 10 minutes. A second consume with the same key is idempotent, while the same token presented with a different key is rejected. A fresh token paired with the same key is an explicit re-authorisation and can restore a previously revoked device.

The remote-executor protocol uses port 8765 by default on an internal or private network. Polls, results, and heartbeats are signed by the device over the exact request bytes. The client verifies server orders and bundles with the key pinned at pairing time. last_heartbeat shows that the process is alive; last_poll separately shows that the worker is requesting work.

7. Revocation and lifecycle

ObjectHow to revoke itEffect
User channelRemove the channel in Settings > System > Users.The address no longer resolves to that user; the associated web cookie fails the binding check.
Low-level Telegram pairing./.venv/bin/python -m runtime.pairing revoke telegram <sender_id>get_pairing no longer returns the active record.
Web sessionExplicit sign-out or acquisition from another device.The write token is marked revoked; the conversation remains owned by the user.
Remote deviceUse the revoke control in Settings > System > Devices.Subsequent polls, results, and heartbeats are rejected; the record remains available for audit.

8. Security invariants

For the general transport contract, see channel; for action approvals, see approvals and human control; for HTTP routes, see http_api.