# Link hub — a guide for a person's own AI


The person's page at `neverlogoff.com/@name` can be the one link they put everywhere. You can set it up for
them with the tools in [`tools-hub.json`](tools-hub.json). Use the same key as the page tools
(`Authorization: Bearer nlou1.…`, made by the person at `/me/page` → "Make a key for my AI").

## Rules

1. **Ask before showing anything.** Any call that would put something on the public page answers
   `409 needs_confirm`. Tell the person exactly what would be shown, wait for a yes, then repeat the call with
   `confirm_public: true`. Never send `confirm_public` on the first try.
2. **Links are https only.** Each link gets a short link `/s/<code>` that counts clicks per day.
3. **Importing from another link page:** fetch the page yourself on the person's computer and parse it
   (`hub-import.js` → `parse(html, url)` does both). Send only
   `{links:[{title,url}]}` to `import_links`. Our server never fetches that page, and refuses HTML.
4. **Accounts:**
   - Twitch, X, YouTube: the person signs in on `/claim`. You cannot do this for them.
   - Bluesky: `connect_account {platform:'bluesky', step:'start', handle}` gives a code. The person puts it
     in their Bluesky profile or a post. Then call `step:'verify'`. This one shows as verified.
   - Mastodon: `step:'start'` tells you what to check. Check it from the person's computer (our server never
     contacts their instance), then `step:'verify', checked:true`. It still shows as "not verified" here.
   - GitHub, Instagram, TikTok: typed in, shown as "not verified".
   - Wallet: only in the person's browser, because the wallet has to sign.
   - Every account starts hidden. `set_account_visibility` → `public` needs a yes.
5. **Counts:** `link_stats` returns totals per day. Days with 1–9 clicks come back as "fewer than 10".
   There is no per-visitor data to ask for.
6. **Look:** `set_theme {id, accent}`. If the colour is refused (`accent_low_contrast`), suggest a darker or
   lighter one. Don't try to get around it.

## Example

```
get_hub
add_link {title:"My shop", url:"https://shop.example.com"}   → 409 needs_confirm
  (ask: "Add 'My shop' to your public page?" → yes)
add_link {title:"My shop", url:"https://shop.example.com", confirm_public:true}
link_stats {days:7}
```
