igneum/relay
igneum-labs 7778dd7cde Miner efficiency sweep: hash per watt per NVIDIA card (lever 3)
src/sweep.rs (new): the cap steps 100% to 50% in 10% steps clamped to the card's limits, per-step rows (mean draw
from nvidia-smi power.draw, mean worker interval rate), the choice (best MH/W, ties to the higher rate then the lower
cap), the nvidia-smi power parser, a state machine on an explicit clock (15 s settle, 60 s hold, 30 s cap readback
limit), the elevated helper scripts (one administrator prompt per sweep: a command file polled by one elevated
process, self-restoring after 20 idle minutes), the unsupported reasons (Apple silicon, AMD). 9 unit tests with
PC 1's recorded RTX 5090 numbers (575 W default, 460 W cap, 290 W draw, memory temperature [N/A]).

Engine: scheduler (once after install, then weekly; one card at a time; only while the card mines, after 120 s
steady, never under a remote job hold, a pause, or inside 600 s of the hour boundary), the cap-mode probe (direct
when the engine runs elevated, else the helper), abort on any fault (card leaves mining, worker error, GPU 90 C,
job, pause, quit) with the cap restored, the chosen cap held and recorded, SWEEP table lines in the app log,
--sweep mode (sweep every supported card, print the table on stdout, leave the caps, quit). Cap floor 50% (was 60).
A readback that matches the asked cap now counts as applied (PC 1 showed "cap NOT applied" for hours at 460 W).

Dashboard: live eff MH/W on each tile, the sweep line (phase, last result, or why unsupported), Sweep now / Stop /
Unpin, "pinned" and "chosen by the sweep" on the cap line, the Settings toggle, the cards-page note, slider min 50.
A cap moved by hand pins the card: the sweep records but does not change it.

PC 1 measurement: relay/playbooks/sweep-5090.ps1 (a run job, elevated, miners stopped; a second engine with --sweep
in a scratch data folder, RESULT SWEEP lines) and docs/plans/miner-eff.md with the publish command. Not published.
Untested on a card.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-10-04 20:38:07 +00:00
..
api Relay: run and task posts need the console token (round 4, X23); prove host saves proofs buffered (ledger P20, second gap) 2026-10-04 18:14:10 +00:00
clients Relay: its own key (relay-key) replaces the intake key for the Mac tools and clients; relay token rotated 4 Oct 2026 (round 4, X23); prove package excludes cross-build folders 2026-10-04 18:25:19 +00:00
lib Relay: text, files and runnable tasks between the Mac, the PCs and the phone (relay.igneum.network) 2026-10-04 10:04:30 +00:00
playbooks Miner efficiency sweep: hash per watt per NVIDIA card (lever 3) 2026-10-04 20:38:07 +00:00
.gitignore Relay: text, files and runnable tasks between the Mac, the PCs and the phone (relay.igneum.network) 2026-10-04 10:04:30 +00:00
apple-touch-icon.png Brand: one master mark (black square, no circle) for every icon, favicon and profile picture 2026-10-04 11:39:55 +00:00
favicon-32.png Brand: one master mark (black square, no circle) for every icon, favicon and profile picture 2026-10-04 11:39:55 +00:00
favicon.ico Brand: one master mark (black square, no circle) for every icon, favicon and profile picture 2026-10-04 11:39:55 +00:00
index.html Brand: one master mark (black square, no circle) for every icon, favicon and profile picture 2026-10-04 11:39:55 +00:00
package-lock.json Relay: text, files and runnable tasks between the Mac, the PCs and the phone (relay.igneum.network) 2026-10-04 10:04:30 +00:00
package.json Relay: text, files and runnable tasks between the Mac, the PCs and the phone (relay.igneum.network) 2026-10-04 10:04:30 +00:00
README.md Relay: its own key (relay-key) replaces the intake key for the Mac tools and clients; relay token rotated 4 Oct 2026 (round 4, X23); prove package excludes cross-build folders 2026-10-04 18:25:19 +00:00
robots.txt Relay: text, files and runnable tasks between the Mac, the PCs and the phone (relay.igneum.network) 2026-10-04 10:04:30 +00:00
ui.html Console Machines tab: app version, OTA state, power cap, jobs and status lines from the app log (0.3.3 header) 2026-10-04 16:50:21 +00:00
vercel.json Igneum console at the relay URL: Machines, Jobs, Builds, Chain, Work log, Results and the relay as tabs 2026-10-04 13:53:33 +00:00

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/relay-key (the relay's own key since 4 October 2026, round 4 X23; the log-intake key no longer opens the relay); 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.