Concurrency: One Controller at a Time#
opendesk serve enforces single-controller by design — at most one
controller machine drives the desktop at a time. Multiple controllers
fighting over a single mouse / keyboard / focused window is the failure
mode this policy prevents.
Different peer trying to connect while one is active → rejected with a clean
BUSYerror. The client sees aProtocolError(“server is busy: laptop is the active controller…”) so the agent knows to back off or ask the operator.Same peer reconnecting (Wi-Fi blip, controller crash, network roam) → bumps the previous session cleanly. No need to wait out the stale TCP connection.
You can still pair as many controllers as you like — they just take turns. To free the slot:
opendesk sessions # show who's active (0 or 1)
opendesk disconnect # ask the active controller to leave (cooperative)
opendesk unpair NAME # revoke trust entirely (enforced)
Disconnect vs unpair — the trust model#
Both commands talk to the running daemon over a local Unix socket /
named pipe (~/.opendesk/admin.sock), not the network — only the user
running serve can use them. They differ in who has the last word:
opendesk disconnectis cooperative. The server sends asession.evictedPUSH frame and closes the connection. A cooperative client (RemoteComputer) sees the frame, suppresses its auto-reconnect, and raisesSessionEvictedon subsequent calls. Trust is preserved — the same controller can come back when it decides to reconnect. A hostile client could ignore the PUSH and reconnect immediately; for that case, useunpair.opendesk unpair NAMEis enforced. The peer is removed from the trusted-peers store, then disconnected (via the same admin IPC channel asdisconnect). Their next reconnect attempt fails authentication outright.
In short: disconnect says “please leave, you can come back later”;
unpair says “you are not welcome here anymore.”
Next: Programmatic Use → — connect from Python or JS code directly.