# Part 5 — devices and key custody

## Listing devices

```ts
const devices = await engine.listDevices();
// [{ deviceId, label, createdAt, revokedAt, current }]
//   current: true for the device you are asking from
```

**Show this list in your UI.** A ghost device — one a malicious relay inserted
to wait for a grant — is only detectable if somebody can see it. It is also
gated: no device is handed a key without either proving it already holds one
or being approved by a person. That is [Part 14](https://docs.thinkingmachinelabs.dev/argala/guide/linking-a-device-and-approving-one.md),
and your app must provide a screen for this part of the linking flow. Key
transparency, which would remove the human from the loop, is on the roadmap
and does not exist yet.

## Linking a second device

The basic exchange is automatic. A new device registers its public keys on
`ArgalaEngine.open`, and any device that already holds the keyring grants it
during an ordinary sync (`autoGrant`, on by default).

```mermaid
sequenceDiagram
  participant N as new device
  participant R as relay
  participant H as an existing device
  N->>R: register pubkeys + selfSig, open graph → status 'waiting'
  H->>R: sync → sees the gap → is this device approved here?
  H->>R: wraps every epoch to N's published pubkey
  N->>R: sync → unwraps → status 'ok'
```

From the app's point of view: the new device shows `waiting` until an existing
device syncs, then flips to `ok`. Tell the user that: _"open the app on your
laptop to finish linking."_

The one step that is not automatic is the middle line. A device that has
already written something the granting device could read is approved silently;
anything else raises `device.pending` and waits for a person. See
[Part 14](https://docs.thinkingmachinelabs.dev/argala/guide/linking-a-device-and-approving-one.md) — under
`linking: 'approve'`, a brand-new device has written nothing yet, so with no
approval screen it sits in `waiting` and nobody can say why.

To drive the ceremony yourself, set `autoGrant: false` and call
`engine.grantPending(graphId)` when you choose.

## What a device holds

```
KeyStore
  device:<deviceId>   ECDH P-256 keypair   — receives wrapped graph keys
  sign:<deviceId>     ECDSA P-256 keypair  — proves authorship
  keyring:<graphId>   { epochs: {1: key, 2: key}, current: 2 }
```

Nothing in that list ever leaves the device except public halves.

---
