A local devnet orchestrator for Lean Ethereum validator clients. Spin up a multi-client devnet with a single command β key generation, genesis, Kubernetes, and metrics included.
curl -fsSL https://raw.githubusercontent.com/shariqnaiyer/leanstart/master/install.sh | bashWorks on macOS (x86_64 + Apple Silicon) and Linux (x86_64 + aarch64). Installs: Rust, kind, kubectl, helm, Docker, and the leanstart binary. Safe to re-run.
| Platform | Docker install |
|---|---|
| macOS | Docker Desktop via Homebrew cask |
| Linux | Docker Engine via get.docker.com |
Note: Docker must be running before launching a devnet. On macOS, open Docker Desktop once after install to complete its setup. On Linux, log out and back in after install to pick up the
dockergroup (or runnewgrp docker).
# Single-client devnet (3 ream pods)
leanstart ream:3
# Multi-client devnet
leanstart ream:2 zeam:2
# Multi-subnet devnet (2 subnets Γ 3 pods each)
leanstart ream:3 --subnets 2Once running, Grafana is at http://localhost:3000 (admin / admin) and Prometheus at http://localhost:9090.
| Client | Image |
|---|---|
ream |
ghcr.io/reamlabs/ream:latest-devnet4 |
zeam |
blockblaz/zeam:devnet4 |
grandine |
sifrai/lean:devnet-4 |
lantern |
piertwo/lantern:v0.0.4 |
qlean |
qdrvm/qlean-mini:devnet-4 |
ethlambda |
ghcr.io/lambdaclass/ethlambda:devnet4 |
Client images are always pulled fresh from the registry on each run.
leanstart [run] <clients...> [options]
run is the default β leanstart ream:3 and leanstart run ream:3 are identical.
Client spec: <name> or <name>:<count> β e.g. ream, zeam:2, grandine:3.
| Flag | Default | Description |
|---|---|---|
--subnets <N> |
1 |
Number of attestation subnets. Each client allocation is replicated once per subnet (max 5) |
--attestation-committee-count <N> |
--subnets |
Override the committee count independently of subnet count |
--validators-per-pod <N> |
1 |
Validators assigned to each pod |
--genesis-offset <secs> |
120 |
Seconds until genesis from now (gives pods time to start) |
--seed <hex> |
0000β¦0001 |
32-byte hex seed for deterministic key generation |
--active-epoch <N> |
18 |
Hash-sig key active epoch exponent (2^N total epochs) |
--bootnode-count <N> |
5 |
Bootnode pods per client type |
--namespace <name> |
lean-devnet |
Kubernetes namespace |
--cluster <name> |
lean-devnet |
Kind cluster name |
--output-dir <path> |
./output |
Directory for generated artifacts |
--skip-kind |
β | Skip Kind cluster creation; use an existing cluster |
--context <ctx> |
β | kubectl/helm context override (required with --skip-kind) |
--skip-metrics |
β | Skip Prometheus + Grafana installation |
--config-only |
β | Generate config files only, skip deployment |
Show pod status for the running devnet.
leanstart status
leanstart status --namespace <name>Tear down the devnet and delete the Kind cluster.
leanstart destroy
leanstart destroy --cluster <name> --namespace <name>Generate all artifacts (keys, genesis, Helm values) without deploying. Useful for inspecting config or deploying to a remote cluster.
leanstart generate --clients ream:2,zeam:2 --subnets 2
leanstart deploy --output-dir ./outputEvery run logs to ./output/runs/<timestamp>/:
output/
βββ genesis/
β βββ config.yaml # Chain config
β βββ genesis.ssz / genesis.json # Genesis state
β βββ nodes.yaml # Bootnode peer list
β βββ annotated_validators.yaml # Validator registry
β βββ hash-sig-keys/ # Hash-sig key pairs per validator
β βββ <pod>.key # libp2p node keys
βββ helm-values.yaml # Helm chart values
βββ secrets/ # Per-pod Kubernetes Secrets
βββ runs/
βββ latest -> <timestamp>/ # Symlink to most recent run
βββ <timestamp>/
βββ run.log # Full orchestration log
βββ <pod>.log # Streaming pod logs
βββ <pod>.previous.log # Previous container logs (on crash)
When metrics are enabled (default), the following are port-forwarded automatically:
| Service | URL | Credentials |
|---|---|---|
| Grafana | http://localhost:3000 | admin / admin |
| Prometheus | http://localhost:9090 | β |
Grafana is pre-configured with two dashboard folders:
- Lean Ethereum Clients β the main client dashboard (set as home)
- Infra β Kubernetes and Prometheus internals
Each pod exposes:
:8080/metricsβ Prometheus metrics:9000β libp2p / QUIC P2P port:5055β HTTP REST API (where supported)
Passing --subnets N replicates each client allocation across N subnets and configures one aggregator per subnet:
# 2 subnets Γ 3 ream pods = 6 pods total
leanstart ream:3 --subnets 2Pod naming in multi-subnet mode: ream-s0-p0, ream-s0-p1, ream-s1-p0, etc.