MLXDocs
MLX Node

Links

Markdown

MLX Node handles mlx:// links. A Mac is linked to a wallet through the wallet's ?link= page and a bind_device transaction.

LinkCommand.parse in mac/MLX/Core/Yield.swift reads every mlx:// link MLX Node is asked to open:

LinkWhat MLX Node does
mlx://apps, mlx://install?app=<id>opens the Apps page, at that app (0.11; never installs by itself). See Apps and updates
mlx://store, mlx://store?app=<slug>, mlx://install?app=<a>,<b>MLX Node 0.17 or later: opens the AI App Store window, at a listing or with up to 20 listings picked to install (never installs by itself). See AI App Store links
any other mlx:// link, such as mlx://openopens the panel (in MLX Node 0.16 and older, mlx://store too)

The action can be the host (mlx://apps) or the path (mlx:apps, mlx:///apps). Names are read without regard to case.

Try it
open "mlx://apps"

Any app on the Mac can open an mlx:// link. A URL scheme carries no caller identity, so none of these links does anything the owner hasn't pressed for: they open the panel, the Apps page or (from 0.17) the AI App Store, and nothing installs by itself.

Linking a Mac to a wallet

MLX Node signs a link request with its device key (linkURL in mac/MLX/Core/API.swift) and opens the wallet with it:

https://wallet.mlx.app/?link=<base64url of the JSON below>
Link payload
{ account, device, name, chip, memoryGB, os, ts, sig }

account is a wallet name, or * for an open request: one the owner approves from whichever wallet they unlock (ANY_WALLET). MLX Node sends open requests. device is the Mac's public key, name its computer name, ts the time in ms. sig is ECDSA P-256 over SHA-256 of this canonical JSON (linkMessage in lib/chain/device.ts):

Signed link message
{"account":"*","chain":"<chain id>","chip":"<chip>","device":"<pk>","memoryGB":<memoryGB>,"name":"<name>","os":"<os>","ts":<ts>,"type":"mlx-device-link"}

The server cleans the name before it checks the signature (control characters removed, trimmed, cut to a maximum length), so MLX Node sends it already clean.

In the wallet

The wallet's link sheet (LinkDeviceSheet in components/wallet/Macs.tsx):

  1. checks the request is for this wallet or open, recent, and signed by the device;
  2. shows the Mac: name, chip, memory, macOS version;
  3. looks the device up with GET /api/device/<pk>, and says so if connecting moves it from another wallet;
  4. asks for the wallet's passkey or recovery phrase, unless the wallet was unlocked or created a moment ago in this same flow;
  5. sends the bind_device transaction.
bind_device body
{ type: "bind_device", device, name, chip?, memoryGB?, os?, ts, proof: <the request's sig> }

Inside MLX Node's panel, the wallet then tells the app with a linked message.

On the ledger

The ledger checks bind_device before it records it:

  • ts is close to the transaction's time;
  • proof is the device's signature over the link message for this wallet, or for *;
  • the proof wasn't used before (devproof:<sha256 of the proof>), and ts is newer than the Mac's current link. Both apply to links from BIND_V2_AT on, so an open request seen on the chain can't be replayed from another wallet;
  • the wallet has fewer than 32 devices.

If the Mac was linked to another wallet, it is removed from that one. A Mac belongs to one wallet at a time. The Mac's record in the wallet holds its key, name, chip, memory, macOS version and the link's time and block.

MLX Node polls GET /api/device/<pk> until at grows, then carries on with setup. See Device lookup.

Unlinking

The wallet sends unbind_device with the device's key. The Mac gets no more jobs for that wallet until it is linked again.

What is public

A Mac's name stays private. Public reads of transactions and accounts show only the kind of Mac ("Linked a MacBook Air"), never its name. The owner sees names in their own wallet and in MLX.app, through signed requests.