26382a7ac6
CI / Clippy (push) Failing after 15m13s
CI / Test (ubuntu-latest) (push) Failing after 16m1s
CI / Test (macos-latest) (push) Has been cancelled
CI / Test (windows-latest) (push) Has been cancelled
CI / Build (no embeddings / no ORT) (push) Has been cancelled
CI / Format (push) Has been cancelled
CI / Cookbook (Node) (push) Has been cancelled
CI / Pi Extension (Node) (push) Has been cancelled
CI / Rust SDK (lean-ctx-client) (push) Has been cancelled
CI / Embed SDK (lean-ctx-sdk) (push) Has been cancelled
CI / Python SDK (leanctx) (push) Has been cancelled
CI / Hermes Plugin (Python) (push) Has been cancelled
CI / SDK Conformance Matrix (push) Has been cancelled
CI / Coverage (push) Has been cancelled
CI / cargo-deny (push) Has been cancelled
CI / Adversarial Safety (push) Has been cancelled
CI / Benchmarks (push) Has been cancelled
CI / Output-Quality Gate (eval A/B) (push) Has been cancelled
CI / Documentation (push) Has been cancelled
CI / CI Green (push) Has been cancelled
JetBrains Plugin / Actionlint (push) Has been cancelled
CodeQL / Analyze (actions) (push) Has been cancelled
CodeQL / Analyze (javascript-typescript) (push) Has been cancelled
CodeQL / Analyze (rust) (push) Has been cancelled
JetBrains Plugin / Validation (push) Has been cancelled
JetBrains Plugin / Build (push) Has been cancelled
JetBrains Plugin / Test (push) Has been cancelled
Security Check / Security Scan (push) Has been cancelled
79 lines
2.5 KiB
Markdown
79 lines
2.5 KiB
Markdown
# Device Overview v1 (GL #387)
|
|
|
|
Per-account list of machines that sync to the Personal Cloud, keyed by the
|
|
client's hostname. Pure display metadata: a device row never participates in
|
|
authentication, entitlements, quota, or billing.
|
|
|
|
## Client behavior
|
|
|
|
Every authenticated sync push attaches one header:
|
|
|
|
```
|
|
X-Device-Label: <hostname>
|
|
```
|
|
|
|
- Source: `gethostname()` on the pushing machine (`cloud_client::device_label`).
|
|
- Attached to: `POST /api/stats`, `POST /api/sync/{knowledge,commands,cep,gotchas,buddy,feedback,gain}`, `PUT /api/sync/index/{project_hash}`.
|
|
- An empty or missing header is valid — the push succeeds, it is just not
|
|
tracked.
|
|
|
|
## Server behavior
|
|
|
|
`devices` table, one row per `(user_id, device_label)`:
|
|
|
|
| column | meaning |
|
|
|---|---|
|
|
| `first_seen` | first push carrying this label |
|
|
| `last_seen` | most recent push |
|
|
| `last_surface` | which sync surface pushed last (`stats`, `knowledge`, …) |
|
|
| `sync_count` | total tracked pushes |
|
|
|
|
Tracking is fire-and-forget (`devices::track`, spawned task): a database
|
|
failure can never fail or slow the sync request itself. Labels are sanitized
|
|
server-side (trimmed, control characters rejected, capped at 64 chars);
|
|
unusable labels are silently skipped.
|
|
|
|
## API
|
|
|
|
### GET /api/account/devices
|
|
|
|
Auth: account bearer. Returns up to 50 devices, most recently active first.
|
|
|
|
```json
|
|
{
|
|
"devices": [
|
|
{
|
|
"label": "mbp-yves",
|
|
"first_seen": "2026-06-01T09:14:00+00:00",
|
|
"last_seen": "2026-06-10T07:02:11+00:00",
|
|
"last_surface": "knowledge",
|
|
"sync_count": 184
|
|
}
|
|
]
|
|
}
|
|
```
|
|
|
|
### DELETE /api/account/devices/{label}
|
|
|
|
Auth: account bearer. Forgets one row; idempotent (`{"forgotten": false}` for
|
|
an unknown label, still HTTP 200 — the end state is identical). Forgetting a
|
|
device deletes nothing else and signs nothing out; the row simply reappears on
|
|
that machine's next sync.
|
|
|
|
`400 bad_label` for labels that fail sanitation (empty / control chars).
|
|
|
|
## UI
|
|
|
|
`/account/cloud` renders the Devices card below usage: hostname, relative
|
|
last-sync time, last surface, push count, and a Forget button per row. The
|
|
card never blocks the dashboard — fetch errors leave it hidden.
|
|
|
|
## Privacy
|
|
|
|
- Hostnames stay within the account that pushed them; no cross-account
|
|
surface, no analytics use.
|
|
- The label is the only machine identifier collected — no MACs, IPs, serials,
|
|
or fingerprints.
|
|
- `DELETE /api/account/devices/{label}` is the user-facing forget control;
|
|
account deletion cascades the whole table (`ON DELETE CASCADE`).
|