relay/api/console.mjs reads the log intake (miner_logs) and console_items in Neon, the OTA manifest, the CI json and the jobs file from the downloads host (DL_TOKEN in the project env, never in the client), and igneum.network/api/live; 10 s cache per answer. tools/console.mjs: post --kind log|build|note, log, machines, chain, jobs, builds, results, sync-bench, sync-dl, sync-hetzner, sync, url. The two Mac-side build scripts post build events. Screenshots at 375 px and desktop in docs/design/console/. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
8.8 KiB
Igneum relay and console
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. Since the evening of 4 October 2026 the same private page is the Igneum console (ui.html): seven tabs, phone first, refreshed every 15 s. The relay feed and drop box are its last tab.
Scope since 4 October 2026 (afternoon): the relay stays for the Mac and for humans (notes, files, tasks for a person or a Claude session on a PC). Commands and files for the PCs themselves go over the line to the Igneum Miner app instead: signed jobs published next to the update manifest (packaging/ota/publish-jobs.sh, read back with tools/jobs.mjs, documented in packaging/ota/README.md, "Remote jobs"). The app jobs replace the PC agent (igneum-agent.bat): PC 2 has no Claude session and nobody at the keyboard, and both PCs report the same hostname (DESKTOP-KMCV30N), which the relay's registration cannot tell apart; the app's per-install machine id can. The playbooks under relay/playbooks/ stay as the relay form of the same runs (shard-test.ps1 is the model for a run job) and are parse-checked by windows.yml.
The console
| Tab | Shows | Source |
|---|---|---|
| Machines | one card per machine: app and node version, height (daa), synced, hash rate, accepted blocks, peers, faults, power and temperatures, last seen; red after 3 min without an upload | Neon miner_logs (the log intake in site/api/log.mjs): newest upload per label, the last 20 KB parsed server side (miner STATUS lines, node log, the app's stability: lines) |
| Jobs | the signed jobs file with per-machine status (queued, running, done + exit code) and the result line; tap a run for the full upload | igneum-jobs.json on the downloads host (fetched server side with DL_TOKEN), results from miner_logs rows whose run_id is job-<id>-<machine> |
| Builds | the OTA manifest (version, notes, platforms, sizes), the last CI fetch, build events, the downloads folder listing | igneum-app-latest.json and igneum-windows-ci.json on the downloads host; console_items kind build (posted by packaging/windows/fetch-ci-artifacts.sh and packaging/ota/publish-manifest.sh) and key dl (tools/console.mjs sync-dl) |
| Chain | blocks, identities, hash estimate, difficulty, last lock, finality state, peers, blocks per minute sparkline, events, Hetzner results | https://igneum.network/api/live fetched server side; console_items key hetzner (sync-hetzner) |
| Work log | what the agents and the main session post, merged with every relay item, newest first | console_items kinds log, build, note; the relay feed |
| Results | the bench log entries (heading + first paragraph), newest first; the FUD ledger counts by status | console_items kind bench and key ledger, written by tools/console.mjs sync-bench from docs/bench-log.md and docs/fud-ledger.md |
| Relay | the feed and the drop box, unchanged | relay_items, relay_machines |
The console function is api/console.mjs, reached through the rewrite /r/<token>/c/<fn>. Every GET answer is cached 10 s in the function instance. No secret reaches the client: the token in the path is the only auth, and DL_TOKEN (the downloads folder) lives in the project env and is used only server side. No GitHub token anywhere: build events come from the Mac-side scripts.
Mac: node tools/console.mjs post --kind log --title "..." --body "..." writes one work-log item (kinds log, build, note); log, machines, chain, jobs, builds, results print the tabs; sync-bench, sync-dl, sync-hetzner or sync push the file-derived data; url prints the link.
Known gap (4 Oct 2026): the app log (label win-<id8> or mac-<id8>) never reaches the intake, because app/igneum-app/src/main.rs names the file with its own stamp_now() while engine.rs uploads app-<engine stamp>.log. Until that is fixed the Machines tab has no app version, no stability: power and temperature lines and no status: lines; everything else comes from the node and miner logs.
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` |
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), DL_TOKEN (the downloads folder token, for the console; added 4 Oct 2026). 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.