# Links

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

## mlx:// links

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

| Link | What 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](/node/apps#links) |
| `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](/store/links) |
| any other `mlx://` link, such as `mlx://open` | opens 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.

```bash title="Try it"
open "mlx://apps"
```

### Who can open these links

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 {#linking-a-mac-to-a-wallet}

### The link request

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

```text
https://wallet.mlx.app/?link=<base64url of the JSON below>
```

```text title="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`):

```json title="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.

```text title="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](/node/worker-protocol#device).

### 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.
