64ca14435cddbd86b1b239cd720a466c9390cf2e
The diff-adjustment tile was showing raw epoch progress (blocks-so-far / 2016 * 100%), which is never what anyone wants to see there. Compute the real predicted change server-side: fetch the timestamp of the first block in the current retarget epoch once per epoch, then each refresh derive (expected_interval / actual_interval - 1) * 100, clamped to Bitcoin's consensus bounds of [-75%, +300%]. The tile now renders the signed percent, green when positive, red when negative. Tile layout is forced to an explicit 5x2 grid so the number of columns doesn't depend on viewport width. Reordering puts the difficulty tile at (row 1, col 5) with the next-adjustment tile directly below it at (row 2, col 5); block height, block reward, total work, and expected block fill the rest of the second row. Mobile breakpoints fall back to 3 and then 2 columns. Header keeps only a live/connecting/offline status dot — the chain name and block height badges were redundant now that the height tile exists and animates on its own. Stat-sub text bumped from 0.85em to 0.95em for readability. Background: a warm ember-glow radial at the top of the viewport layered with two accent radials and a low-opacity haori-checker tile pattern (inline SVG data URI). Cards get a translucent backdrop so the texture peeks through between them.
Kamado Pool
A modern, feature-complete solo Bitcoin mining pool built on a patched fork of CKPool, with a real-time web dashboard and a Go-based API middleware that surfaces everything CKPool knows.
Why Kamado?
Existing CKPool-based solutions (like Bassin for Umbrel) read only a handful of periodic stats files and miss most of CKPool's rich data. Kamado talks directly to CKPool's Unix socket API to expose:
- Real-time per-client data: hashrate, difficulty, user agent, hardware detection
- Full block-found history with height, hash, reward, and solving worker
- Per-worker and per-client best share tracking (current + all-time)
- Network difficulty, pool efficiency, expected time to block
- Live dashboard updates via WebSocket (no 60-second file polls)
Architecture
┌────────────────────────────────────────────────────┐
│ ckpool-solo (C) ──Unix socket──► kamado-api (Go) │
│ ports: 3333 ports: 80 │
│ │
│ ▲ stratum ▲ HTTP/WS │
│ │ │ │
│ Miners Browser │
│ │
│ bitcoind ◄──── RPC + ZMQ ────── ckpool + kamado-api│
└────────────────────────────────────────────────────┘
Three main components:
| Component | Language | Purpose |
|---|---|---|
ckpool/ |
C | Stratum server, share validation, block submission |
api/ |
Go | Socket client, REST/WebSocket API, persistence |
ui/ |
Svelte | Real-time dashboard |
Phases
- Phase 1 — Fork & fix CKPool, build infrastructure
- [~] Phase 2 — Go API middleware
- Phase 2a: CKPool socket client, bitcoind RPC, state aggregator, REST API
- Phase 2b: CKPool log tailer, block history, stdlib WebSocket push
- Phase 2b.5: ZMQ block notifier, SQLite persistence (deferred until s9pk repo exists — need real Go build env for new deps)
- ckpool patch 0001: expose
besteverin runtime socket JSON so the UI can show "this round" and "all-time" best share side by side - [~] Phase 3 — Svelte UI dashboard (skeleton: header, pool overview, miners table, blocks, best shares leaderboard; live WS updates)
- Phase 4 — Monorepo Docker build:
kamado-apiembedsui/distvia//go:embedand serves it at/. The api Dockerfile has a node stage that builds the UI before the Go stage embeds and builds the binary; docker-compose uses the repo root as build context so bothapi/andui/are visible. - Phase 5 — Testing (regtest, testnet4), polish
Quick start (dev)
cp .env.example .env # set POOL_BTCADDRESS and bitcoind creds
make up # build + start ckpool + api
curl localhost:8080/api/health
curl localhost:8080/api/pool
REST endpoints:
| Route | Returns |
|---|---|
GET /api/health |
CKPool + bitcoind health |
GET /api/pool |
Pool stats + derived hashrate windows + chain info |
GET /api/users |
All users from users socket command |
GET /api/workers |
All workers from workers socket command |
GET /api/clients |
All connected stratum sessions (useragent, IP, diff) |
GET /api/blocks |
Recent solved blocks (in-memory ring, SQLite in Phase 2b.5) |
GET /api/snapshot |
Full merged snapshot (everything) |
GET /api/ws |
WebSocket push: full snapshot on every refresh + on solve |
StartOS packaging lives in a separate repository.
Upstream
CKPool by Con Kolivas: https://bitbucket.org/ckolivas/ckpool
Pinned commit: see ckpool/CKPOOL_COMMIT
License
GPL-3.0. CKPool itself is distributed under GPL-3.
Languages
Go
46.7%
Svelte
36.4%
Shell
9.2%
TypeScript
4.7%
Dockerfile
1.4%
Other
1.5%