You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
status today is a thin passthrough: svc_status (rigforge.sh:2603-2610) runs systemctl status on Linux and mac_status (rigforge.sh:2534-2545) prints one "running / not running" line on macOS. Neither answers the question an operator actually walks up with: is it hashing, at what rate, on which pool, and are shares landing? Today that takes logs plus squinting, or a manual curl against the worker API. The API already has everything in one endpoint (/2/summary), and RigForge already has a tested reader for it (_read_api_hashrate, rigforge.sh:2328-2343). One fetch, five lines, done.
Scope
When the miner is up, status prints a compact RigForge summary block FIRST, then the existing platform block (systemd on Linux, the mac_status line on macOS) unchanged below it. Summary first because it's the glance; systemd detail is the drill-down.
Summary fields, all from ONE /2/summary fetch: hashrate (.hashrate.total[0]), pool + connection (.connection.pool), miner uptime (.uptime, seconds — render as 1d 4h 23m), accepted/rejected shares (.connection.accepted / .connection.rejected), huge pages (.hugepages // empty — the field exists on our pinned XMRig 6.26.0; verify during implementation and drop the line silently if empty).
No sudo, ever — keep the existing comment at rigforge.sh:2608 ("don't prompt for a password to look") and extend its spirit to the new block. No log-file grep for huge pages: the service log can be root-owned, and doctor already owns the log-based check (rigforge.sh:3018-3023). The API field or nothing.
Degrade gracefully: API unreachable (miner stopped, still starting, or http disabled) → the platform block prints exactly as today, plus one line: RigForge: worker API not reachable at 127.0.0.1:8080 (miner stopped or still starting).
macOS gets the identical summary block appended to mac_status — the API runs there too (the miner is a nohup background process or a launchd login agent, rigforge.sh:2494-2545, using the same generated config with the same http block).
Output format decision: plain aligned printf ' %-10s %s\n' "Hashrate:" "..." key/value lines — NOT the _ck_ok/_ck_warn/∙ markers (rigforge.sh:2735-2737). Rationale: status reports facts; ✓/! imply a pass/fail judgment, which is doctor's job. Plain lines also stay grep-friendly.
Out of scope: watchdog logic, thresholds, exit codes based on hashrate, --json output. No new config keys — the summary is derived entirely from the existing API and ACCESS_TOKEN handling.
Acceptance criteria
status with an active miner shows hashrate, pool URL, uptime, accepted/rejected shares in one block, then the unchanged systemd output; total of ONE curl to the API.
status with the miner stopped shows the systemd block exactly as today plus the single "worker API not reachable" line; exit code unchanged (still 0).
With ACCESS_TOKEN set in config.json, the fetch sends the Bearer header; without it, no Authorization header (same contract as _read_api_hashrate — the existing Bearer test at tests/run.sh:1463-1486 stays green untouched).
status never invokes sudo and never prompts.
Works on macOS: status with a running miner shows the same summary block after the existing mac_status line.
A missing or invalid config.json cannot crash status — the platform block still prints.
Tests cover: summary rendering from a stubbed API body, the unreachable branch, and the Bearer/no-Bearer paths. make lint clean; suite passes on macOS bash 3.2 and Linux.
Implementation notes
Numbered, mechanical. All design decisions are made — do not reopen them.
Extract _read_api_summary() directly above _read_api_hashrate (rigforge.sh:2328). Move the curl + Bearer-branch body there verbatim (the branch comment at rigforge.sh:2335-2337 moves with it — it documents a real 401/set-e trap), minus the trailing jq. It prints the raw /2/summary JSON, or nothing if curl is missing/unreachable.
Rewire _read_api_hashrate to keep its exact external contract: the API_CMD eval branch stays FIRST and unchanged (tests at tests/run.sh:1309, 1338, 1362, 1403 stub it with a bare number — API_CMD output bypasses jq, do not route it through _read_api_summary); otherwise _read_api_summary | jq -r '.hashrate.total[0] // empty' 2>/dev/null.
New _status_api_summary() near svc_status (rigforge.sh:2603): fetch once into a local (body=$(_read_api_summary)), bail with the one-line unreachable message if empty, else ONE jq -r extracting all fields (a single jq invocation emitting tab-separated values, read into locals — one fork, bash-3.2-safe), then the aligned printf block. Render uptime seconds as Nd Nh Nm with a tiny arithmetic helper (integer math only; no bc).
parse_config inside a subshell.ACCESS_TOKEN only exists after parse_config, and parse_config calls error (which exit 1s) on a bad config — || true does NOT catch exit in the current shell. So svc_status runs the whole summary as ( parse_config >/dev/null 2>&1 && _status_api_summary ) || true — a bad/missing config degrades to just the platform block.
svc_status becomes: subshell summary (note 4), then the existing systemctl status ... || true line unchanged (keep the rigforge.sh:2608 no-sudo comment). mac_status (rigforge.sh:2534): keep its current lines, append the same subshell summary call at the end. OS_TYPE gating is already handled by the svc_status dispatch at rigforge.sh:2604-2607.
Docs: update the status line in usage() (rigforge.sh:3049, "show whether the miner is running" → mention the live summary) and the corresponding line in docs/operations.md.
Tests (tests/run.sh): extend the curl stub at tests/run.sh:173-179 — its printf body currently emits only {"hashrate":...}; add connection (pool/accepted/rejected/uptime), top-level uptime, and hugepages fields (existing assertions only parse hashrate, so this is additive). Copy the subshell-runner shape of the doctor block (tests/run.sh:1921-1966: run_doctor() sources $SCRIPT, overrides paths, captures output; assert_contains at tests/run.sh:43). New block: (a) source + PATH="$STUBS:$PATH" + call svc_status with a stubbed systemctl, assert pool/hashrate/accepted values appear; (b) point curl at a failing stub (exit 7) and assert the "not reachable" line plus the systemctl passthrough; (c) re-run the existing Bearer assertions pattern against _read_api_summary if the refactor moved the header logic (the feat: worker HTTP API open (read-only) by default #125 block at tests/run.sh:1463-1486 must stay green as-is).
Verification:make lint (shellcheck 0.11 warning + shfmt -i 4), make test, then on miner-0: rigforge status while mining (summary + systemd), sudo systemctl stop xmrig && rigforge status (unreachable line + inactive systemd block), and once with ACCESS_TOKEN set.
Pitfalls: bash 3.2 (no associative arrays, no ${var,,}); set -Eeuo pipefail — every jq/curl in the summary path needs || true/// empty guards so a half-up API can't abort status; exit inside error/parse_config is only containable in a subshell (note 4); don't print ACCESS_TOKEN anywhere; no new config keys, so config.reference.json is untouched.
Why
statustoday is a thin passthrough:svc_status(rigforge.sh:2603-2610) runssystemctl statuson Linux andmac_status(rigforge.sh:2534-2545) prints one "running / not running" line on macOS. Neither answers the question an operator actually walks up with: is it hashing, at what rate, on which pool, and are shares landing? Today that takeslogsplus squinting, or a manual curl against the worker API. The API already has everything in one endpoint (/2/summary), and RigForge already has a tested reader for it (_read_api_hashrate, rigforge.sh:2328-2343). One fetch, five lines, done.Scope
statusprints a compact RigForge summary block FIRST, then the existing platform block (systemd on Linux, themac_statusline on macOS) unchanged below it. Summary first because it's the glance; systemd detail is the drill-down./2/summaryfetch: hashrate (.hashrate.total[0]), pool + connection (.connection.pool), miner uptime (.uptime, seconds — render as1d 4h 23m), accepted/rejected shares (.connection.accepted/.connection.rejected), huge pages (.hugepages // empty— the field exists on our pinned XMRig 6.26.0; verify during implementation and drop the line silently if empty).httpdisabled) → the platform block prints exactly as today, plus one line:RigForge: worker API not reachable at 127.0.0.1:8080 (miner stopped or still starting).mac_status— the API runs there too (the miner is anohupbackground process or a launchd login agent, rigforge.sh:2494-2545, using the same generated config with the samehttpblock).printf ' %-10s %s\n' "Hashrate:" "..."key/value lines — NOT the_ck_ok/_ck_warn/∙markers (rigforge.sh:2735-2737). Rationale:statusreports facts; ✓/! imply a pass/fail judgment, which is doctor's job. Plain lines also stay grep-friendly.Out of scope: watchdog logic, thresholds, exit codes based on hashrate,
--jsonoutput. No new config keys — the summary is derived entirely from the existing API andACCESS_TOKENhandling.Acceptance criteria
statuswith an active miner shows hashrate, pool URL, uptime, accepted/rejected shares in one block, then the unchanged systemd output; total of ONE curl to the API.statuswith the miner stopped shows the systemd block exactly as today plus the single "worker API not reachable" line; exit code unchanged (still 0).ACCESS_TOKENset in config.json, the fetch sends the Bearer header; without it, no Authorization header (same contract as_read_api_hashrate— the existing Bearer test at tests/run.sh:1463-1486 stays green untouched).statusnever invokes sudo and never prompts.statuswith a running miner shows the same summary block after the existingmac_statusline.status— the platform block still prints.make lintclean; suite passes on macOS bash 3.2 and Linux.Implementation notes
Numbered, mechanical. All design decisions are made — do not reopen them.
_read_api_summary()directly above_read_api_hashrate(rigforge.sh:2328). Move the curl + Bearer-branch body there verbatim (the branch comment at rigforge.sh:2335-2337 moves with it — it documents a real 401/set-e trap), minus the trailingjq. It prints the raw/2/summaryJSON, or nothing if curl is missing/unreachable._read_api_hashrateto keep its exact external contract: theAPI_CMDeval branch stays FIRST and unchanged (tests at tests/run.sh:1309, 1338, 1362, 1403 stub it with a bare number —API_CMDoutput bypasses jq, do not route it through_read_api_summary); otherwise_read_api_summary | jq -r '.hashrate.total[0] // empty' 2>/dev/null._status_api_summary()nearsvc_status(rigforge.sh:2603): fetch once into a local (body=$(_read_api_summary)), bail with the one-line unreachable message if empty, else ONEjq -rextracting all fields (a singlejqinvocation emitting tab-separated values,readinto locals — one fork, bash-3.2-safe), then the alignedprintfblock. Render uptime seconds asNd Nh Nmwith a tiny arithmetic helper (integer math only; nobc).parse_configinside a subshell.ACCESS_TOKENonly exists afterparse_config, andparse_configcallserror(whichexit 1s) on a bad config —|| truedoes NOT catchexitin the current shell. Sosvc_statusruns the whole summary as( parse_config >/dev/null 2>&1 && _status_api_summary ) || true— a bad/missing config degrades to just the platform block.svc_statusbecomes: subshell summary (note 4), then the existingsystemctl status ... || trueline unchanged (keep the rigforge.sh:2608 no-sudo comment).mac_status(rigforge.sh:2534): keep its current lines, append the same subshell summary call at the end.OS_TYPEgating is already handled by thesvc_statusdispatch at rigforge.sh:2604-2607.statusline inusage()(rigforge.sh:3049, "show whether the miner is running" → mention the live summary) and the corresponding line in docs/operations.md.{"hashrate":...}; addconnection(pool/accepted/rejected/uptime), top-leveluptime, andhugepagesfields (existing assertions only parse hashrate, so this is additive). Copy the subshell-runner shape of the doctor block (tests/run.sh:1921-1966:run_doctor()sources$SCRIPT, overrides paths, captures output;assert_containsat tests/run.sh:43). New block: (a) source +PATH="$STUBS:$PATH"+ callsvc_statuswith a stubbedsystemctl, assert pool/hashrate/accepted values appear; (b) point curl at a failing stub (exit 7) and assert the "not reachable" line plus the systemctl passthrough; (c) re-run the existing Bearer assertions pattern against_read_api_summaryif the refactor moved the header logic (the feat: worker HTTP API open (read-only) by default #125 block at tests/run.sh:1463-1486 must stay green as-is).make lint(shellcheck 0.11 warning + shfmt -i 4),make test, then on miner-0:rigforge statuswhile mining (summary + systemd),sudo systemctl stop xmrig && rigforge status(unreachable line + inactive systemd block), and once withACCESS_TOKENset.Pitfalls: bash 3.2 (no associative arrays, no
${var,,});set -Eeuo pipefail— every jq/curl in the summary path needs|| true/// emptyguards so a half-up API can't abortstatus;exitinsideerror/parse_configis only containable in a subshell (note 4); don't printACCESS_TOKENanywhere; no new config keys, so config.reference.json is untouched.Related