igneum/relay/README.md
igneum-labs 53f7f55796 Relay: text, files and runnable tasks between the Mac, the PCs and the phone (relay.igneum.network)
New Vercel project igneum-relay from relay/: one function (api/relay.mjs) over Neon tables relay_items and relay_machines,
files in Vercel Blob store igneum-relay (50 MB client uploads, 4 MB through the function), phone-first web page at /r/<token>/
with the site tokens. Mac CLI tools/relay.mjs (feed, read, drop, task, run, watch, inbox, machines, role, name).
Windows clients send.bat/send.ps1 and the igneum-agent (registers hostname, role, GPUs, WSL, nvcc; runs queued PowerShell
scripts, posts results, reboot-continue via scheduled task + RunOnce), bash twins send.sh and agent.sh (verified live),
playbooks for WSL setup, prover setup, prove-block, miner v4, one-click placeholder. make-clients.sh bakes the secrets
into a zip; the repo copies hold placeholders. Screenshots under docs/design/relay.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-04 10:04:30 +00:00

55 lines
4.8 KiB
Markdown

# Igneum relay
Text, files and tasks between the project lead's devices without Gmail: the Mac, PC1, PC2 and the phone post to one feed and read from it. Vercel project `igneum-relay`, served at https://relay.igneum.network. Built 4 October 2026.
## The secret is the path
The web page lives at `/r/<token>/` and every API call sits under `/r/<token>/api/<fn>`. The token is 20 base32 characters generated once and stored at `~/.config/igneum/relay-token` on the Mac (and as `RELAY_TOKEN` in the project). Anyone with the link can read and post, so the link stays with the project lead. Scripts may present the log intake key in `x-igneum-key` instead (`RELAY_KEY`, the same value as `~/.config/igneum/log-intake-key`). There is no other login. Blob file URLs carry a random segment and a random suffix; they are not listed anywhere.
## What is stored where
| Thing | Where | Limit |
|---|---|---|
| Items (text, title, who, kind, flags, read and done marks) | Neon table `relay_items` (database `igneum`) | body 1 MB |
| Machines (name, hostname, role, GPU and WSL facts, last seen) | Neon table `relay_machines` | |
| Files | Vercel Blob store `igneum-relay` (public URLs with random path and suffix, London) | 50 MB per file through a client token; 4 MB when pushed through the function |
| The token and key | `~/.config/igneum/relay-token`, `~/.config/igneum/log-intake-key`; project env | never in the repo |
Kinds: `text` (a note), `file`, `task` (for a person or a Claude session on a PC), `run` (a script the agent executes), `result` (what a task produced, linked by `task_id`). Roles: `miner`, `prover`, `bench`, `mac`, `phone`.
## API (all under `/r/<token>/api/`)
| Call | Does |
|---|---|
| `GET feed?since=&before=&machine=&limit=` | items newest first (200 by default) plus every machine with its unread count |
| `GET item?id=` | one item with its full body |
| `GET file?id=[&download=1]` | 302 to the file |
| `GET inbox?machine=PC1&kind=run|task&ack=1` | unread, not done tasks for that machine; `ack=1` marks them read |
| `GET machines` | names, roles, hostnames, last seen |
| `POST drop` | JSON `{from,to,kind,title,body,file_name,file_url,size,task_id,flags}`; or raw bytes with `Content-Type: application/octet-stream` and `x-file-name` (4 MB cap) |
| `POST task` | same fields; `kind` `task` or `run`; `run` needs one named machine and flags `{elevated, reboot_continue}` |
| `POST upload` | `{name,size}` returns a one-hour Blob client token and `put_url`; PUT the bytes there, then `drop` with the returned `url` |
| `POST ack {ids}` `POST done {id,exit_code}` `POST delete {id}` | marks |
| `POST register {hostname,info}` | a machine checks in; returns its name, role and whether it is named |
| `POST name {hostname,name}` `POST role {name,role}` | naming and roles, from the Mac |
## Mac
`node tools/relay.mjs` (feed), `read <id>`, `drop "<text>"|<file>`, `task PC2 "title" [file]`, `run PC2 "title" script.ps1 [--elevated] [--reboot-continue]`, `watch`, `inbox PC1`, `machines`, `role PC2 prover`, `name DESKTOP-XYZ PC2`, `ack|done|rm <id>`, `url`. Playbooks live in `relay/playbooks/`; `run` fills `__DL_BASE__` in from `~/.config/igneum/dl-token`.
## PCs
`relay/clients/make-clients.sh` bakes the URL, key and token into copies of the clients and writes `~/Desktop/igneum-relay-clients.zip`. Unzip anywhere on the PC. `send.bat` for people and Claude sessions (see `CLAUDE-PC.md`), `igneum-agent.bat` for the automatic runner: double-click once, leave it open. It registers the PC (hostname, GPUs, WSL, nvcc), polls every 20 s, runs each `run` task in order, posts a `result` (exit code, last 64 KB inline, full log as a file when longer) and marks it done. A script that prints `RELAY-REBOOT` triggers `shutdown /r /t 10`; with `reboot_continue` the agent re-arms (scheduled task at logon with highest privileges, RunOnce as a fallback) and re-runs the task after the restart with `RELAY_PASS` incremented. The PC must sign in by itself for that to be unattended.
An unknown hostname that registers appears in the feed with a "name this machine" box, or `node tools/relay.mjs name <hostname> PC2`. PC1 is DESKTOP-KMCV30N.
## Deploy
```
cd relay && npx --yes vercel@latest --global-config ~/.config/igneum/vercel deploy --prod --yes --scope igneum
```
Env on the project: `DATABASE_URL`, `RELAY_KEY`, `RELAY_TOKEN`, `BLOB_READ_WRITE_TOKEN` (added by `vercel blob create-store`). DNS: `relay` CNAME `cname.vercel-dns.com` in the deSEC zone.
## Untested until a PC runs it (4 Oct 2026)
`send.ps1`, `igneum-agent.ps1` and the five PowerShell playbooks were written and syntax-reviewed on the Mac (no `pwsh` here). The bash twin `agent.sh` and `send.sh` ran end to end against the live relay. Expect a first-run fix on Windows: `Start-Process -Wait` exit codes through the wrapper, `wsl --install --no-launch` on pass 2, the RunOnce path after a reboot.