Single source of truth for the v1.1 release plan. This issue sequences the milestone v1.1 work into ordered waves so humans and agents can see what to do next and why , not just what's left . The milestone says what ships in 1.1; this issue says in what order and what blocks what . (Same format as the v1.0 roadmap #167 .)
How to use this
Pick up the lowest-numbered wave with unfinished work. Within a wave, follow the listed order (it encodes intra-wave dependencies).
Every issue carries a wave-N-* label, so you can query directly, e.g. is:open is:issue milestone:v1.1 label:wave-2-privacy.
Check the box here when an issue closes (GitHub keeps the cross-references live).
Status (updated 2026-06-17): Wave 1 ✅ DONE (PR #265 ). Wave 2 ✅ DONE: the Tor-default flips #165 + #166 are merged to develop. But validating them on gouda surfaced that the stack's "behind Tor" guarantee is per-app config — and fragile : p2pool leaked clearnet on a stale image, and Tari leaks despite a correct type=tor config. So Wave 2 grew the real fix — #270 enforce Tor-only egress at the network layer (fail-closed) + #274 a standing egress-leak harness check — and #256 is now blocked until the all-Tor arm proves clean (a leaking arm is an invalid benchmark). New issues from this: #270 #271 #273 #274 (privacy) and #272 (e2e tested stale images). #270 is now merged (PR #275 ) and live-validated on gouda — the firewall yields the first clean all-Tor PASS (all four apps 0 public; the Tari #271 leak is dropped). Validation also surfaced #276 (firewall installed after compose up left a startup window — fixed + validated in PR #277 ). #271 (Tari) is now FIXED — PR #285 merged — proxy_bypass_for_outbound_tcp=false routes Tari's clearnet peer dials through Tor SOCKS (validated on gouda: 0 direct-public, peers via Tor), so with #162 's DNS sinkhole Tari is fully Tor-only. Tor coverage is now complete (every app Tor-routed + fail-closed backstop); Wave 2 is now COMPLETE — #165 /#166 /#270 /#276 /#271 /#273 /#274 + the enablers #272 /#278 are all merged; the stack is genuinely all-Tor AND mining (live-validated on gouda). The one remaining v1.1-privacy step is the #256 benchmark RUN (multi-day), now unblocked. v1.1 remains the deferred-privacy + hardening + observability release. Wave 7 added (2026-06-16): a parallel developer-tooling & supply-chain track (epic #279 , children #280 –#284 , #286 , #292 ) — starts after Wave 2 , runs alongside Waves 3–5; its supply-chain scanning child (#282 ) lands before v1.1 images publish.
Branching: v1.1 work lands on develop (now the repo default); main stays at the released state and merges from develop only at release. See [[dev-branch-workflow]]. Validate a branch end-to-end on gouda with tests/integration/e2e.sh <branch> (lean by default).
The theme: v1.0 closed the privacy leaks ; v1.1 makes "behind Tor" the default — and structural , then makes that posture visible . The Tor-default flips (#165 /#166 ) are merged; the long pole is now #270 — proving (and enforcing) that everything is genuinely behind Tor — the benchmark (#256 ) waits behind it, then everything else parallelizes off the result.
Critical path (what gates "can we ship 1.1?")
#165 + #166 Tor-default flips ✅ merged to develop
│
▼
#270 enforce Tor-only egress (fail-closed) + #274 egress-leak harness check ✅ DONE — proven behind Tor
│ (✅ #271 Tari, #273 p2pool-coupling, #272 e2e-rebuild, #278 p2pool↔monerod — all fixed + merged)
▼
#256 benchmark Tor-vs-clearnet (multi-day; sets the FINAL #165/#166 defaults) ← READY TO RUN — all blockers cleared
│
└─► #160 epic closes ─► #170 Component Health panel ─► #80 launch assets ─► SHIP 1.1
Parallel tracks (off the critical path)
Wave 1 ✅ done. While the privacy spine (#270 → #274 → #256 ) proceeds, these run independently and can be picked up in any order by available hands/agents:
Wave 3 stratum (RigForge: fetch the stratum access-password at worker setup → default-on stratum auth (Phase 2 of #152) #208 → Stratum-over-TLS: encrypt the miner↔stack stratum link (follow-on to stratum auth #208) #261 ) — cross-repo with RigForge; its own sequential pair.
Wave 5 hardening (Run containers as a non-root user (drop root inside the container) #255 , Security follow-ups: dashboard host-networking, Tari gRPC allow-list, assert_safe_dir #91 , e2e: optional tier-4 live validation for already-unit-tested security features #206 ) — infra/container hardening; e2e.sh deploys with pithead apply (--pull, not --build) → tests STALE first-party images #272 (e2e rebuild) is here and high-leverage (it unblocks trustworthy validation of the privacy work).
Wave 6 docs (Licensing hygiene: third-party attribution + GPLv3 compliance for published images #259 , Docs: edit out the AI-generated voice (the 'no X, no Y' tell) — make the docs read like a human wrote them #258 , docs(faq): update the "vs. Gupax" comparison — Gupax now bundles node/proxy/XvB #257 ) — independent docs/licensing; only Launch assets: refreshed hero screenshot + demo GIF + GitHub social preview #80 in this wave is gated (on the final UI).
Wave 7 tooling ([Epic] Developer tooling & code-quality stack — professionalize the repo #279 epic → tooling: Python lint + format with ruff (+ .editorconfig, pre-commit) #280 –tooling: correctness — hypothesis property tests + ruff ANN→ty roadmap #284 , tooling: adopt RigForge's CI best practices (diff-cover patch coverage + checksum-verified pinned tool installs) #286 , governance: add a Contributor License Agreement (CLA) for inbound contributions #292 ) — developer tooling, code-quality & supply-chain hardening; starts after Wave 2 , parallel to Waves 3–5. Mostly internal DX, so independent of the privacy spine — except the supply-chain scanning child (tooling: supply-chain & secrets hardening (gitleaks, Dependabot, Trivy, SHA-pinned actions + zizmor) #282 ), which lands before v1.1 images publish (with Licensing hygiene: third-party attribution + GPLv3 compliance for published images #259 ).
Wave 1 — Cleanup & test debt wave-1-cleanup ✅ DONE (PR #265 → develop)
Zero-dependency warm-ups. Self-contained, low-risk, parallelizable — cleared first.
Wave 2 — Privacy defaults wave-2-privacy ✅ DONE — only the #256 benchmark RUN remains
Flip the yield-trade-off paths to Tor — then PROVE the whole stack is actually behind Tor before trusting the benchmark. Validating the flips on gouda surfaced that config-level Tor routing is fragile (p2pool leaked on a stale image; Tari leaks despite a correct type=tor), so the real work is now the structural guarantee, not just the per-app flips.
The flips — merged to develop:
Make "everything behind Tor" real + provable:
Enforce Tor-only egress at the network layer (fail-closed) — stop relying on per-app config #270 — Enforce Tor-only egress at the network layer (fail-closed) — the real guarantee: app containers get no clearnet route except the Tor SOCKS , so any per-app leak fails closed. ✅ merged (PR feat(privacy): enforce Tor-only egress fail-closed via a host firewall (#270) #275 ) + live-validated on gouda : with the firewall on, bench-verify-egress.sh tor is a clean all-Tor PASS (monerod/p2pool/tari/xmrig all 0 public); Tari's clearnet dials (Tari (minotari) dials some peers over clearnet despite transport type = "tor" #271 ) are dropped from the start.
Promote bench-verify-egress.sh into the live harness as a standing no-clearnet-leak check #274 — Promote bench-verify-egress.sh to a standing harness check (PR feat(#274): standing no-clearnet-leak egress gate in the harness #288 — refined to persistent-only; the --check harness phase now gates on 0 app clearnet connections) (no clearnet leaks; persistent-connection check) — the proof of Enforce Tor-only egress at the network layer (fail-closed) — stop relying on per-app config #270 .
Tari (minotari) dials some peers over clearnet despite transport type = "tor" #271 — Tari dials some peers over clearnet despite type=tor — root-caused + FIXED (PR fix(privacy): route Tari clearnet peer dials through Tor SOCKS — genuinely behind Tor (#271) #285 , merged): minotari defaults proxy_bypass_for_outbound_tcp=true, so it direct-dials peers advertising bare /ip4 addresses; set false → every dial routes via Tor SOCKS (peers reached via Tor exits). Live-validated on gouda: 0 direct-public; peers dialed via Tor (up to 36 SOCKS conns) — functional vs the prior blocked-dead state. With Tari: eliminate clearnet DNS leaks (DNS seeds + Tari Pulse), fix misleading DoT comment #162 's DNS sinkhole, Tari is now fully Tor-only (no clearnet TCP or DNS). Upstream issues filed: Privacy: proxy_bypass_for_outbound_tcp defaults to true — a type = "tor" base node still direct-dials clearnet peers (leaks operator IP) tari-project/tari#7883 (privacy-hostile proxy_bypass default), Privacy: Tari Pulse service cannot be disabled — unconditional checkpoint DNS lookups with no off-switch tari-project/tari#7884 (Pulse has no off-switch).
p2pool flags silently dropped on a 'new compose + old image' partial update (#165 coupling) #273 — p2pool flags silently dropped on a stale-image partial update (PR fix(#273): fail-loud when a stale p2pool image drops the Tor flags #289 — pithead doctor fails loudly when a stale image isn't applying --socks5).
Then the gate:
5. [ ] #256 — Benchmark Tor vs clearnet while mining (multi-day; sets the FINAL #165 /#166 defaults before release) . READY TO RUN — all blockers cleared (#270 /#274 /#272 /#278 merged; the stack is all-Tor and mining, validated on gouda — clean [verify-egress] OK + p2pool pulling full block templates). Collector + methodology landed (PR #268 , draft).
6. [x] #160 — [Epic] Privacy: no clearnet egress outside Tor — CLOSED; the structural guarantee (per-app Tor + #270 fail-closed firewall) landed.
Wave 3 — Stratum hardening wave-3-stratum
Miner↔stack link: access control, then confidentiality. Cross-repo with RigForge; a sequential pair, independent of the privacy spine.
RigForge: fetch the stratum access-password at worker setup → default-on stratum auth (Phase 2 of #152) #208 — RigForge fetches the stratum access-password at setup → default-on stratum auth (Phase 2 of Optional stratum access-password: require miners to authenticate to xmrig-proxy #152 ; makes authenticated stratum the zero-friction default, like PROXY_AUTH_TOKEN). Stack-side tracking issue; impl lives in RigForge.
Stratum-over-TLS: encrypt the miner↔stack stratum link (follow-on to stratum auth #208) #261 — Stratum-over-TLS: encrypt the miner↔stack link (follow-on to RigForge: fetch the stratum access-password at worker setup → default-on stratum auth (Phase 2 of #152) #208 — TLS for confidentiality, password for access control; orthogonal, usable together). Worker side = rigforge#115.
Wave 4 — Dashboard observability & XvB wave-4-dashboard
The screenshot surface. #263 is independent (slot it early); #170 waits on the Wave-2 flips so it shows the final posture.
Wave 5 — Container & infra hardening wave-5-hardening
Lower-priority hardening; runs in parallel. #206 shares #256 's live-mining infra.
Run containers as a non-root user (drop root inside the container) #255 — Run containers as a non-root user (drop uid 0 in monerod/p2pool/xmrig-proxy/dashboard; builds on the Pre-launch hardening sweep (stratum bind, no-new-privileges/cap_drop, healthcheck creds, p2pool healthcheck) #90 cap/no-new-privileges work). The crux is volume ownership — pick one pattern (fixed uid / PUID+PGID / named volume) and apply it consistently.
Security follow-ups: dashboard host-networking, Tari gRPC allow-list, assert_safe_dir #91 — Security follow-ups (dashboard network_mode: host → bridge, trim Tari gRPC allow-list, tighten assert_safe_dir). Self-scoped post-launch hardening; each item resolved or consciously closed.
e2e: optional tier-4 live validation for already-unit-tested security features #206 — e2e: optional tier-4 live validation for already-unit-tested security features (worker-SSRF guard, public-IP warning, XvB-stats-over-Tor via tcpdump). Companion to e2e: assert an empty PROXY_AUTH_TOKEN makes the stack refuse to start (#153) #203 ; piggybacks on the Benchmark Tor vs clearnet while mining (p2pool / monerod / Tari) — does steady-state mining lose yield over Tor? #256 live-mining environment.
e2e.sh deploys with pithead apply (--pull, not --build) → tests STALE first-party images #272 — e2e.sh rebuilds STALE first-party images on deploy ✅ (PR fix(#272): e2e deploys via pithead upgrade so it tests the branch's rebuilt images #287 ) — deploy now uses pithead upgrade (re-render + --build); exposed p2pool can't reach its local monerod when Tor is on — #165's --socks5 also proxies the monerod RPC (stack doesn't mine on the default) #278 .
p2pool can't reach its local monerod when Tor is on — #165's --socks5 also proxies the monerod RPC (stack doesn't mine on the default) #278 — p2pool can't reach its local monerod when Tor is on ✅ (PR fix(#278): keep p2pool's monerod RPC/ZMQ direct under Tor — restores mining on the Tor default #290 ) — root cause: p2pool: route outbound sidechain P2P through Tor by default (--socks5), documented clearnet opt-out #165 's --socks5 proxied the local monerod RPC through Tor; a socat loopback bridge keeps the node DIRECT while the sidechain rides Tor. Restored mining on the Tor default.
Wave 6 — Docs & launch wave-6-release ⬅ FINISH LINE
Independent docs land any time; #80 is gated on the final dashboard UI.
Wave 7 — Tooling & code health wave-7-tooling (parallel track, after Wave 2)
Status (2026-06-18): ✅ COMPLETE. All children merged — #280
Make Pithead a professionally-tooled project: every file surface under a linter + formatter + CI gate , glued by pre-commit, plus the supply-chain gaps closed (secret scanning, dep/image CVE alerts, SHA-pinned actions, a lockfile). Extends the existing posture (SHA256-verified binaries, digest-pinned bases #135 ) to the currently-unguarded surfaces. Distinct from the product waves — it's developer tooling — so it gets its own track. Epic: #279 .
tooling: Python lint + format with ruff (+ .editorconfig, pre-commit) #280 — Python lint + format with ruff (+ .editorconfig, pre-commit) — the foundation the rest plugs into; the format-only commit lands separately from the lint gate.
tooling: round out per-surface lint/format (shfmt, Biome, yamllint, markdownlint, buf) #281 — Round out per-surface lint/format — shfmt (shell), Biome (JS/CSS/JSON), yamllint, markdownlint + lychee (docs), buf (proto).
tooling: supply-chain & secrets hardening (gitleaks, Dependabot, Trivy, SHA-pinned actions + zizmor) #282 — Supply-chain & secrets hardening — gitleaks, Dependabot (pip/actions/docker), Trivy image scan, SHA-pinned actions + zizmor. Lands before v1.1 images publish (with Licensing hygiene: third-party attribution + GPLv3 compliance for published images #259 ). Highest security ROI of the initiative.
tooling: reproducible Python builds with uv + uv.lock #283 — Reproducible Python builds — uv + hashed uv.lock across Dockerfile/CI/release; closes the last unpinned supply-chain surface after Pin base/runtime images by digest (caddy, docker-socket-proxy, tari, ubuntu, python) to match SECURITY.md's stated posture #135 .
tooling: correctness — hypothesis property tests + ruff ANN→ty roadmap #284 — Correctness — hypothesis property tests for the money/numeric logic (cf. the XvB split controller overshoots target tier ~3× (catch-up windup during API ramp) #70 overshoot bug); ruff ANN → ty roadmap (deferred — not a v1.1 blocker ).
tooling: adopt RigForge's CI best practices (diff-cover patch coverage + checksum-verified pinned tool installs) #286 — Adopt RigForge's CI best practices — diff-cover patch-coverage gate (vs our flat 80%) + checksum-verified pinned tool installs. Back-port: RigForge's shell CI is ahead of ours here (also tooling: round out per-surface lint/format (shfmt, Biome, yamllint, markdownlint, buf) #281 shfmt, tooling: supply-chain & secrets hardening (gitleaks, Dependabot, Trivy, SHA-pinned actions + zizmor) #282 SHA-pinned actions).
governance: add a Contributor License Agreement (CLA) for inbound contributions #292 — Governance: Contributor License Agreement / DCO — record inbound-contribution IP terms and enforce them on every PR (recommended low-friction default: DCO Signed-off-by + the DCO GitHub App as a required status check; a formal CLA only if relicensing/patent grants are ever needed). It's a PR gate + a contribution-process doc, independent of the linters — lands any time. Pairs with Licensing hygiene: third-party attribution + GPLv3 compliance for published images #259 as the inbound-licensing counterpart to that outbound-licensing work. Org-wide trio — the same mechanism must land in RigForge (rigforge#119) and the site (p2pool-starter-stack.github.ioImprove Readme to highlight Sync Mode #10 ).
Cross-issue dependencies (live)
This…
…waits for
Why
#256 (benchmark)
#270 + #274
✅ both merged + live-validated (clean all-Tor PASS)
#256 (benchmark)
#272 (e2e rebuild)
✅ PR #287 — harness rebuilds first-party images on deploy
#256 (benchmark)
#278 (p2pool↔monerod)
✅ PR #290 — #165 's --socks5 was proxying the node RPC; socat loopback bridge keeps it direct. Restores mining on the Tor default.
#270 (egress enforcement)
—
contains #271 (Tari leak) structurally; #273 hardens the #165 image coupling
#165 / #166 (Tor-default)
#256 → merged; final default confirmed by #256 before release
flips landed behind the toggle; #256 sets whether the default stays Tor
#160 (epic)
#165 + #166 + #270
now closes on the structural guarantee, not just the per-app flips
#170 (Component Health panel)
#165 + #166 + #270
should reflect the final all-Tor posture, not a mid-flip state
#261 (stratum TLS)
#208 (stratum auth default-on)
TLS is the explicit follow-on; composes on top of the auth knob
#80 (launch assets)
#170 + #263
screenshots need the final dashboard UI
#206 (tier-4 live e2e)
#256 infra
shares the live-mining test-server matrix
v1.1 image publish
#282 (supply-chain scanning) + #259 (licensing)
don't publish v1.1 images with unscanned CVEs/secrets or missing third-party attribution
#281 / #282 (other Wave 7 children)
#280 (ruff + pre-commit)
#280 establishes the pre-commit runner the other tooling hooks plug into
Cross-repo companions (RigForge + website)
v1.1 (this release — ships in lockstep with RigForge v1.1):
RigForge: fetch the stratum access-password at worker setup → default-on stratum auth (Phase 2 of #152) #208 ↔ rigforge#113 (default-on auth) — the secret-fetch lives in RigForge; this is the pithead-side tracker.
Stratum-over-TLS: encrypt the miner↔stack stratum link (follow-on to stratum auth #208) #261 ↔ rigforge#115 (worker-side pools[].tls: true).
Wave 7 tooling [Epic] Developer tooling & code-quality stack — professionalize the repo #279 ↔ rigforge#116 (companion tooling epic). RigForge is pure shell, so it gets a smaller, different set — only the language-agnostic gaps: tooling: supply-chain & secrets hardening (gitleaks, Dependabot, Trivy, SHA-pinned actions + zizmor) #282 ↔ rigforge#117 (gitleaks/Dependabot-actions/zizmor), tooling: Python lint + format with ruff (+ .editorconfig, pre-commit) #280 /tooling: round out per-surface lint/format (shfmt, Biome, yamllint, markdownlint, buf) #281 ↔ rigforge#118 (.editorconfig/pre-commit/yamllint/markdownlint+lychee). Note RigForge is ahead of us on shfmt (tooling: round out per-surface lint/format (shfmt, Biome, yamllint, markdownlint, buf) #281 ), SHA-pinned actions (tooling: supply-chain & secrets hardening (gitleaks, Dependabot, Trivy, SHA-pinned actions + zizmor) #282 ), and patch-coverage + verified tool installs (tooling: adopt RigForge's CI best practices (diff-cover patch coverage + checksum-verified pinned tool installs) #286 ) — all now tracked as Pithead back-ports. The website runs the same track (site#16/Add Testing #11 /Add XvB and P2Pool calculator #12 /Set memory limit for tari container to 2048m #14 ) — see the Website block below.
Governance / CLA governance: add a Contributor License Agreement (CLA) for inbound contributions #292 ↔ rigforge#119 ↔ p2pool-starter-stack.github.ioImprove Readme to highlight Sync Mode #10 — an org-wide trio; all three repos adopt the same mechanism (DCO recommended) so contributors get one process. The site issue must also pick a LICENSE first (it has none — likely code MIT + content CC-BY-4.0).
Website (p2pool-starter-stack.github.io, "site#" below) — v1.1, mostly Wave-7 companions:
The showcase site runs a parallel tooling + governance track that mirrors Wave 7 — track it here alongside the RigForge companions (site issues live under the site's own v1.1/v1.2 milestones).
Tooling ↔ Wave 7: site#16 (.editorconfig/Prettier/markdownlint) ↔ tooling: Python lint + format with ruff (+ .editorconfig, pre-commit) #280 /tooling: round out per-surface lint/format (shfmt, Biome, yamllint, markdownlint, buf) #281 ↔ rigforge#118 · site#11 (SHA-pin actions/Dependabot/zizmor/gitleaks) ↔ tooling: supply-chain & secrets hardening (gitleaks, Dependabot, Trivy, SHA-pinned actions + zizmor) #282 ↔ rigforge#117 (supply-chain — lands before the site's prod deploys, mirroring tooling: supply-chain & secrets hardening (gitleaks, Dependabot, Trivy, SHA-pinned actions + zizmor) #282 before image publish) · site#12 (lychee dead-link monitoring) ↔ tooling: round out per-surface lint/format (shfmt, Biome, yamllint, markdownlint, buf) #281 ↔ rigforge#118 · site#14 (codespell/cspell + Vale prose lint) ↔ tooling: round out per-surface lint/format (shfmt, Biome, yamllint, markdownlint, buf) #281 /Docs: edit out the AI-generated voice (the 'no X, no Y' tell) — make the docs read like a human wrote them #258 ↔ rigforge#118.
Governance: site#17 (CODEOWNERS, issue/PR templates, SECURITY.md) — the site counterpart to repo hygiene already in pithead · site#10 (CLA) is the org-wide trio above (↔ governance: add a Contributor License Agreement (CLA) for inbound contributions #292 ↔ rigforge#119).
Site-only (no pithead/rigforge companion): site#15 (single-source the Hugo version + a bump mechanism) · site#13 (Lighthouse CI budgets — perf/a11y/SEO/best-practices). v1.2: site#1 (faux/demo dashboard preview with dummy data).
v1.5 (fleet — tracked here for visibility; RigForge files these under its own v1.5 milestone):
Explicitly NOT in v1.1 (later milestones)
v1.2 — Tailscale remote access [Investigate] Tailscale (mesh VPN) for secure remote dashboard access — the response path to #79/#121 alerts (opt-in, default off) #262 , Telegram alerting Telegram alerting (notifications-only): node/worker down + recovered (config.json, default off) #121 , outage flagging Flag outages / significant hashrate-loss events on the chart (+ feed Telegram/Healthchecks alerts) #99 , Healthchecks dead-man's-switch Healthchecks.io dead-man's-switch: detect power loss / host-down via external ping (config.json, default off) #79 (the deferred Wave-4 alerting pair, now with its richer v1.2 siblings) .
v1.3 — telemetry-persistence epic [Epic] Persist valuable telemetry as time-series — stop discarding block / share-health / disk-growth / XvB / per-worker data #196 + Store share stats as time-series for reject-rate trends/charting #116 , dashboard calculators Add Tari (merge-mining) earnings to the dashboard calculator #117 /Add XvB tier / raffle calculator to the dashboard #118 , cadence/luck Pool cadence & luck panel (time-to-share, time-since-block, luck %, PPLNS weight) #84 , setup-warning badges Surface setup/host warnings as dashboard badges (AVX2, HugePages, low disk/RAM) #104 , db-failure e2e e2e: fault-inject a dashboard DB write failure and assert db_healthy=false (#131) #202 .
v1.4 — upgrade button Dashboard: new-version warning + one-click upgrade button #59 , config editor Stack config editor: change any setting from the dashboard, applied via pithead (incl. P2Pool mode hot-swap) #33 , CLI completion pithead CLI: shell tab-completion + safe chaining of subcommands #94 .
v1.5 — energy/profit calculator Dashboard: energy & profit calculator — net profit (earnings − power cost), from RigForge's power telemetry #260 , primary/backup sync [Feature] Sync Primary + Backup Stacks #249 , RigForge enriched feed [Feature] Dashboard: consume RigForge's enriched feed (rigforge#99) — update badge + per-worker health / power / tune / firmware #235 (↔ rigforge#99) , Worker Inspect Dashboard: Worker Inspect page — read/edit each miner's XMRig config over its API, with versioned config history + per-config hashrate stats #185 , custom-token/ports Dashboard: config to read workers that use a custom XMRig API token #171 /Configurable worker ports & endpoints: non-standard stratum/API ports + per-worker host/port/token overrides (later) #172 , Telegram bot Telegram interactive bot / command interface (query stack status over Telegram) #45 , RigForge↔Pithead integration tests Integration tests: RigForge worker ↔ Pithead xmrig-proxy (end-to-end flows) #209 (↔ rigforge#114) .
v1.6 — co-hosting [Feature/Discussion] Support co-hosting via migration guides and relaxed reverse-proxy/network bindings #181 , remote Tari node Evaluate a remote Tari base-node option (tari.mode: remote), mirroring Monero remote #103 , non-default-subnet e2e e2e: deploy a NON-default network.subnet in the live matrix (#180) #201 .
v2 (appliance) — bootable installers Bootable USB installers: self-provisioning appliance images for the stack host and RigForge miner #77 , Podman/Quadlet Evaluate Podman + Quadlet as the container runtime for the immutable appliance (vs Docker Compose) #78 , remote node-starter repos Far-off: appliance-style Monero (and Tari) node-starter repos for easy remote nodes #105 .
How to use this
wave-N-*label, so you can query directly, e.g.is:open is:issue milestone:v1.1 label:wave-2-privacy.Status (updated 2026-06-17): Wave 1 ✅ DONE (PR #265). Wave 2 ✅ DONE: the Tor-default flips #165 + #166 are merged to
develop. But validating them on gouda surfaced that the stack's "behind Tor" guarantee is per-app config — and fragile: p2pool leaked clearnet on a stale image, and Tari leaks despite a correcttype=torconfig. So Wave 2 grew the real fix — #270 enforce Tor-only egress at the network layer (fail-closed) + #274 a standing egress-leak harness check — and #256 is now blocked until the all-Tor arm proves clean (a leaking arm is an invalid benchmark). New issues from this: #270 #271 #273 #274 (privacy) and #272 (e2e tested stale images). #270 is now merged (PR #275) and live-validated on gouda — the firewall yields the first clean all-Tor PASS (all four apps 0 public; the Tari #271 leak is dropped). Validation also surfaced #276 (firewall installed aftercompose upleft a startup window — fixed + validated in PR #277). #271 (Tari) is now FIXED — PR #285 merged —proxy_bypass_for_outbound_tcp=falseroutes Tari's clearnet peer dials through Tor SOCKS (validated on gouda: 0 direct-public, peers via Tor), so with #162's DNS sinkhole Tari is fully Tor-only. Tor coverage is now complete (every app Tor-routed + fail-closed backstop); Wave 2 is now COMPLETE — #165/#166/#270/#276/#271/#273/#274 + the enablers #272/#278 are all merged; the stack is genuinely all-Tor AND mining (live-validated on gouda). The one remaining v1.1-privacy step is the #256 benchmark RUN (multi-day), now unblocked. v1.1 remains the deferred-privacy + hardening + observability release. Wave 7 added (2026-06-16): a parallel developer-tooling & supply-chain track (epic #279, children #280–#284, #286, #292) — starts after Wave 2, runs alongside Waves 3–5; its supply-chain scanning child (#282) lands before v1.1 images publish.Critical path (what gates "can we ship 1.1?")
pithead apply(--pull, not --build) → tests STALE first-party images #272/p2pool can't reach its local monerod when Tor is on — #165's --socks5 also proxies the monerod RPC (stack doesn't mine on the default) #278 cleared the e2e + mining blockers). Benchmark Tor vs clearnet while mining (p2pool / monerod / Tari) — does steady-state mining lose yield over Tor? #256 is unblocked — it just needs the several days of live data.Parallel tracks (off the critical path)
Wave 1 ✅ done. While the privacy spine (#270 → #274 → #256) proceeds, these run independently and can be picked up in any order by available hands/agents:
pithead apply(--pull, not --build) → tests STALE first-party images #272 (e2e rebuild) is here and high-leverage (it unblocks trustworthy validation of the privacy work).Wave 1 — Cleanup & test debt
wave-1-cleanup✅ DONE (PR #265 → develop)Zero-dependency warm-ups. Self-contained, low-risk, parallelizable — cleared first.
known_workerspersistence layer (orphaned by the proxy-sourced worker rewrite; pure refactor, no behavior change)tar --no-xattrsinscripts/release.sh; cosmetic,good first issue)PROXY_AUTH_TOKENmakes the stack refuse to start (live validation of the xmrig-proxy HTTP API: enforce authentication (fail closed if the access token is empty) #153 fail-closed guard; independent)tests/integration/e2e.shgouda branch-runner + Remove dead known_workers persistence layer (orphaned by the proxy-sourced worker rewrite) #144/Release bundle carries macOS xattrs → 'LIBARCHIVE.xattr.com.apple.provenance' warnings on Linux extract #252 regression tests (in the same PR).Wave 2 — Privacy defaults
wave-2-privacy✅ DONE — only the #256 benchmark RUN remainsFlip the yield-trade-off paths to Tor — then PROVE the whole stack is actually behind Tor before trusting the benchmark. Validating the flips on gouda surfaced that config-level Tor routing is fragile (p2pool leaked on a stale image; Tari leaks despite a correct
type=tor), so the real work is now the structural guarantee, not just the per-app flips.The flips — merged to
develop:--socks5,p2pool.clearnetopt-out). Confirmed routing over Tor once the image is rebuilt.xvb.toropt-out;--donate-level 0already pinned).Make "everything behind Tor" real + provable:
bench-verify-egress.sh toris a clean all-Tor PASS (monerod/p2pool/tari/xmrig all 0 public); Tari's clearnet dials (Tari (minotari) dials some peers over clearnet despite transport type = "tor" #271) are dropped from the start.compose up(PR fix(privacy): install Tor-egress firewall before containers start — close startup window (#276) #277) — follow-up found during validation: installing after compose left a startup window where Tari opened clearnet connections theESTABLISHEDrule grandfathered (observed 2–3 public peers on a freshup). Fixed + validated (0 public at t+0).bench-verify-egress.shto a standing harness check (PR feat(#274): standing no-clearnet-leak egress gate in the harness #288 — refined to persistent-only; the--checkharness phase now gates on 0 app clearnet connections) (no clearnet leaks; persistent-connection check) — the proof of Enforce Tor-only egress at the network layer (fail-closed) — stop relying on per-app config #270.type=tor— root-caused + FIXED (PR fix(privacy): route Tari clearnet peer dials through Tor SOCKS — genuinely behind Tor (#271) #285, merged): minotari defaultsproxy_bypass_for_outbound_tcp=true, so it direct-dials peers advertising bare/ip4addresses; setfalse→ every dial routes via Tor SOCKS (peers reached via Tor exits). Live-validated on gouda: 0 direct-public; peers dialed via Tor (up to 36 SOCKS conns) — functional vs the prior blocked-dead state. With Tari: eliminate clearnet DNS leaks (DNS seeds + Tari Pulse), fix misleading DoT comment #162's DNS sinkhole, Tari is now fully Tor-only (no clearnet TCP or DNS). Upstream issues filed: Privacy:proxy_bypass_for_outbound_tcpdefaults to true — atype = "tor"base node still direct-dials clearnet peers (leaks operator IP) tari-project/tari#7883 (privacy-hostile proxy_bypass default), Privacy: Tari Pulse service cannot be disabled — unconditional checkpoint DNS lookups with no off-switch tari-project/tari#7884 (Pulse has no off-switch).pithead doctorfails loudly when a stale image isn't applying--socks5).Then the gate:
5. [ ] #256 — Benchmark Tor vs clearnet while mining (multi-day; sets the FINAL #165/#166 defaults before release). READY TO RUN — all blockers cleared (#270/#274/#272/#278 merged; the stack is all-Tor and mining, validated on gouda — clean
[verify-egress] OK+ p2pool pulling full block templates). Collector + methodology landed (PR #268, draft).6. [x] #160 — [Epic] Privacy: no clearnet egress outside Tor — CLOSED; the structural guarantee (per-app Tor + #270 fail-closed firewall) landed.
Wave 3 — Stratum hardening
wave-3-stratumMiner↔stack link: access control, then confidentiality. Cross-repo with RigForge; a sequential pair, independent of the privacy spine.
PROXY_AUTH_TOKEN). Stack-side tracking issue; impl lives in RigForge.Wave 4 — Dashboard observability & XvB
wave-4-dashboardThe screenshot surface. #263 is independent (slot it early); #170 waits on the Wave-2 flips so it shows the final posture.
Wave 5 — Container & infra hardening
wave-5-hardeningLower-priority hardening; runs in parallel. #206 shares #256's live-mining infra.
no-new-privilegeswork). The crux is volume ownership — pick one pattern (fixed uid /PUID+PGID/ named volume) and apply it consistently.network_mode: host→ bridge, trim Tari gRPC allow-list, tightenassert_safe_dir). Self-scoped post-launch hardening; each item resolved or consciously closed.pithead apply(--pull, not --build) → tests STALE first-party images #272 —e2e.shrebuilds STALE first-party images on deploy ✅ (PR fix(#272): e2e deploys viapithead upgradeso it tests the branch's rebuilt images #287) — deploy now usespithead upgrade(re-render +--build); exposed p2pool can't reach its local monerod when Tor is on — #165's --socks5 also proxies the monerod RPC (stack doesn't mine on the default) #278.--socks5proxied the local monerod RPC through Tor; a socat loopback bridge keeps the node DIRECT while the sidechain rides Tor. Restored mining on the Tor default.Wave 6 — Docs & launch
wave-6-release⬅ FINISH LINEIndependent docs land any time; #80 is gated on the final dashboard UI.
THIRD_PARTY_LICENSES.md+ GPLv3 source pointers for the pinned p2pool/xmrig-proxy binaries). Should land before we publish v1.1 images.Wave 7 — Tooling & code health
wave-7-tooling(parallel track, after Wave 2)ruff(+.editorconfig,pre-commit) — the foundation the rest plugs into; the format-only commit lands separately from the lint gate.shfmt(shell), Biome (JS/CSS/JSON),yamllint,markdownlint+lychee(docs),buf(proto).uv+ hasheduv.lockacross Dockerfile/CI/release; closes the last unpinned supply-chain surface after Pin base/runtime images by digest (caddy, docker-socket-proxy, tari, ubuntu, python) to match SECURITY.md's stated posture #135.hypothesisproperty tests for the money/numeric logic (cf. the XvB split controller overshoots target tier ~3× (catch-up windup during API ramp) #70 overshoot bug); ruffANN→tyroadmap (deferred — not a v1.1 blocker).diff-coverpatch-coverage gate (vs our flat 80%) + checksum-verified pinned tool installs. Back-port: RigForge's shell CI is ahead of ours here (also tooling: round out per-surface lint/format (shfmt, Biome, yamllint, markdownlint, buf) #281 shfmt, tooling: supply-chain & secrets hardening (gitleaks, Dependabot, Trivy, SHA-pinned actions + zizmor) #282 SHA-pinned actions).Signed-off-by+ the DCO GitHub App as a required status check; a formal CLA only if relicensing/patent grants are ever needed). It's a PR gate + a contribution-process doc, independent of the linters — lands any time. Pairs with Licensing hygiene: third-party attribution + GPLv3 compliance for published images #259 as the inbound-licensing counterpart to that outbound-licensing work. Org-wide trio — the same mechanism must land in RigForge (rigforge#119) and the site (p2pool-starter-stack.github.ioImprove Readme to highlight Sync Mode #10).Cross-issue dependencies (live)
#256 (benchmark)#270 + #274#256 (benchmark)#272 (e2e rebuild)#256 (benchmark)#278 (p2pool↔monerod)#256→ merged; final default confirmed by #256 before releasepre-commitrunner the other tooling hooks plug intoCross-repo companions (RigForge + website)
v1.1 (this release — ships in lockstep with RigForge v1.1):
pools[].tls: true)..editorconfig/pre-commit/yamllint/markdownlint+lychee). Note RigForge is ahead of us on shfmt (tooling: round out per-surface lint/format (shfmt, Biome, yamllint, markdownlint, buf) #281), SHA-pinned actions (tooling: supply-chain & secrets hardening (gitleaks, Dependabot, Trivy, SHA-pinned actions + zizmor) #282), and patch-coverage + verified tool installs (tooling: adopt RigForge's CI best practices (diff-cover patch coverage + checksum-verified pinned tool installs) #286) — all now tracked as Pithead back-ports. The website runs the same track (site#16/Add Testing #11/Add XvB and P2Pool calculator #12/Set memory limit for tari container to 2048m #14) — see the Website block below.p2pool-starter-stack.github.ioImprove Readme to highlight Sync Mode #10 — an org-wide trio; all three repos adopt the same mechanism (DCO recommended) so contributors get one process. The site issue must also pick aLICENSEfirst (it has none — likely code MIT + content CC-BY-4.0).Website (
p2pool-starter-stack.github.io, "site#" below) — v1.1, mostly Wave-7 companions:The showcase site runs a parallel tooling + governance track that mirrors Wave 7 — track it here alongside the RigForge companions (site issues live under the site's own
v1.1/v1.2milestones)..editorconfig/Prettier/markdownlint) ↔ tooling: Python lint + format with ruff (+ .editorconfig, pre-commit) #280/tooling: round out per-surface lint/format (shfmt, Biome, yamllint, markdownlint, buf) #281 ↔ rigforge#118 · site#11 (SHA-pin actions/Dependabot/zizmor/gitleaks) ↔ tooling: supply-chain & secrets hardening (gitleaks, Dependabot, Trivy, SHA-pinned actions + zizmor) #282 ↔ rigforge#117 (supply-chain — lands before the site's prod deploys, mirroring tooling: supply-chain & secrets hardening (gitleaks, Dependabot, Trivy, SHA-pinned actions + zizmor) #282 before image publish) · site#12 (lychee dead-link monitoring) ↔ tooling: round out per-surface lint/format (shfmt, Biome, yamllint, markdownlint, buf) #281 ↔ rigforge#118 · site#14 (codespell/cspell + Vale prose lint) ↔ tooling: round out per-surface lint/format (shfmt, Biome, yamllint, markdownlint, buf) #281/Docs: edit out the AI-generated voice (the 'no X, no Y' tell) — make the docs read like a human wrote them #258 ↔ rigforge#118.v1.5 (fleet — tracked here for visibility; RigForge files these under its own v1.5 milestone):
Explicitly NOT in v1.1 (later milestones)