leo pair¶
Pair a phone (the Leo iOS app) or Leo.app's menu bar with this machine's daemon.
Usage¶
Description¶
leo pair prints a QR code and a one-line JSON payload — {daemon_id, name, urls, pairing_code}. The urls are web.public_urls when set, otherwise the web listener's LAN addresses. The pairing code works once and expires after 5 minutes. Redeeming it issues the device its own bearer token; manage paired devices with leo devices list and leo devices revoke <id>.
Warnings (a loopback-only listener, a LAN URL missing from web.allowed_hosts) go to stderr. With the web listener disabled the command fails; leo web enable turns it on.
--json¶
Prints one JSON object instead of a QR code, for the Leo.app menu bar (which draws the QR itself):
{
"daemon_id": "9f2c…",
"name": "studio-mac",
"urls": ["https://leo.example.com"],
"pairing_code": "…",
"warnings": [],
"expires_at": "2026-10-20T23:10:00Z",
"qr_payload": "{\"daemon_id\":\"9f2c…\",\"name\":\"studio-mac\",\"urls\":[…],\"pairing_code\":\"…\"}"
}
| Field | Meaning |
|---|---|
daemon_id, name, urls, pairing_code | The payload fields, as printed in text mode. |
warnings | Always an array; empty when there is nothing to flag. |
expires_at | RFC 3339 UTC time the code stops working. |
qr_payload | The exact string to encode as the QR code. Encode this, not a re-serialisation of the other fields. |
stdout carries only the object. With the web listener off it is exactly {"error":"web_disabled"} and the exit status is non-zero (the app then offers leo web enable). Other failures are {"error":"config_error"|"pairing_failed","message":"…"}. See the JSON rule.