Pop CLI

Pop CLI

Pop CLI is the all-in-one command-line interface for Polkadot development, built by R0GUE with funding from the Web3 Foundation's Decentralized Futures program. It unifies project scaffolding, building, testing, chain and smart contract interaction, and local network orchestration into a single tool. Our contributions were born from a clear goal — the ability to spawn a local Polkadot network in seconds, with a single command.

The Problem

Polkadot development has a steep onboarding curve. Before Pop CLI, launching a local test network was a multi-step ordeal. Developers had to source relay and system chain binaries manually — locating and downloading prebuilt releases when available, or building from source when not, a process that could take upwards of thirty minutes. Network configuration added another layer of complexity: TOML files encoding validators, parachain identifiers, collator settings, and HRMP channel definitions. Every project required its own setup, and every SDK update risked breaking it. For a tool that aspired to be the single entry point for Polkadot development, the gap between scaffolding a project and actually running it was the critical missing piece.

Our Contributions

Our 70+ contributions spanned the full breadth of the project — from foundational feature implementation through performance rework, developer experience refinement, and engineering standards that raised the bar for all contributors.

Network Launching

Our core contribution was the pop up command — the ability to launch a complete local Polkadot network in seconds. The initial implementation introduced network orchestration powered by zombienet-sdk — the Rust SDK for programmatically spawning Polkadot networks. Pop CLI focused on the developer experience, handling what the SDK doesn't: resolving and sourcing the required node binaries (downloading prebuilt releases where available, building from source otherwise), caching them locally, and adapting the network configuration accordingly — closing the gap between scaffolding a project and launching it on a local network.

From there, the feature evolved through a series of architectural reworks. Multi-network support added Paseo, Kusama, and Polkadot chain-spec generation using a declarative Runtime enum with strum annotations — making future network support a matter of adding an enum variant. Faster binary sourcing replaced the original git-clone-and-build approach with direct GitHub release downloads, turning lengthy build times into local networks in seconds. The config-free launch culmination eliminated the TOML configuration requirement entirely — enabling developers to declaratively specify their network requirements at runtime.

Usage data validates the investment: up is consistently a top-3 command, demonstrating that local network launching is as essential to the development workflow as building and testing.

Developer Experience

Several contributions reduced friction across the tool. Auto-detected builds made pop build introspect the workspace manifest to determine project type automatically, eliminating the need for explicit parachain or contract subcommands. A Status trait streamed compiler output to progress indicators, turning opaque build waits into a visible pipeline. The Cli trait and MockCli — introduced alongside the pop clean command for cache management — established a testable abstraction over terminal interactions that became foundational for maintaining the developer experience as the tool evolved.

Performance & Reliability

Beyond the sourcing rework described above, we addressed production-grade reliability concerns. A dedicated ApiClient replaced scattered reqwest calls with rate-limit tracking, retry-after handling, semaphore-bounded concurrency, and test-mode response caching — eliminating flaky CI failures caused by GitHub API rate exhaustion. Container fixes improved usage of the tool within containers, alongside a Dockerfile rewrite and CI enforcement to prevent regressions.

Code Quality & Engineering Standards

We restructured the test suite, relocating long-running tests from inline source modules to dedicated integration test files — enabling parallelisation of CI jobs, cutting feedback cycles, and making the test structure self-documenting. Clippy enforcement resolved warnings across the project and added CI gating to prevent regressions.

cargo-deny added dependency vulnerability and license compliance checks — a meaningful addition for a workspace with hundreds of transitive crates from the Polkadot SDK ecosystem. A documentation pass completed the public API surface documentation across every crate, with rustdoc warnings promoted to errors in CI. Code coverage via cargo-llvm-cov and Codecov established observability into test quality.

Individually modest changes, but collectively they raised the project's quality baseline and operational maturity for all subsequent contributors.

Technical Highlights

A closer look at the key abstractions and design decisions behind the contributions.

Platform-Aware Binary Sourcing

A Source enum with Archive, Git, GitHub(ReleaseArchive | SourceCodeArchive), and Url variants. ReleaseArchive implements version resolution with TagPattern regex parsing, configurable version comparators, local cache scanning, fallback versions, and staleness detection — enabling automatic upgrades when newer releases are available. When prebuilt binaries are unavailable, SourceCodeArchive and Git variants provide a fall back to source builds with streamed compiler output via a Status trait. Downloads use retry middleware with exponential backoff on transient failures.

Config-Free Network Orchestration

A chain registry backed by a Chain meta-trait composing Args, Binary, ChainSpec, GenesisOverrides, Node, Requires, and Source. The Requires trait maps chain dependencies by TypeId to genesis override closures, enabling the CLI to auto-detect and auto-add them with the correct genesis configuration. This enables chain requirements to be modelled in code rather than configuration files, simplifying orchestration and ensuring everything needed is available on network launch. The registry is initialised once via OnceLock per relay chain, with an impl_chain! macro and AsChain blanket impls reducing per-chain boilerplate to a single struct.

The config-free launch uses BuildCommand<const FILTER: u8> — a const generic encoding the relay chain variant index — so each subcommand (pop up paseo, pop up kusama) restricts --parachain values via a SupportedChains parser to only those registered for that network at compile time.

Testable CLI Abstraction

The Cli trait wraps cliclack, mirroring its interactive prompt API — confirmations, selections, inputs, password prompts, and progress reporting. MockCli records expectations via builders (expect_confirm, expect_input, expect_select) that are consumed as trait methods are called, with verify() panicking if any expectations remain unsatisfied — enabling deterministic testing of interactive command flows without terminal I/O.

API Resilience

ApiClient wraps reqwest with tokio::sync::Semaphore-bounded concurrency, parsed x-ratelimit-* and retry-after headers stored in shared Arc<Mutex<RateLimits>> state, and a #[cfg(test)] response cache that memoises by URL — so test suites hit the network once per unique endpoint regardless of how many tests exercise the same API call.

Outcome

What started as a practical need — launching local Polkadot networks quickly — grew into sustained open-source contribution across the full surface area of the project. The pop up feature we built from scratch is now one of the most-used commands in the tool, and the engineering standards we introduced continue to shape every contribution that follows. More broadly, the experience reinforced a pattern we've seen across our work: the most impactful contributions often come from solving your own problems in the open.

Pop CLI is open source under GPL-3.0. Explore the project on GitHub or get started at onpop.io.

An all-in-one tool for Polkadot development.

github.com/r0gue-io/pop-cli

Industry

Web3 / Developer Tooling

Let's start something

Interested in what's possible? We'd like to hear about it.

Get in touch

By browsing this website, you accept our Privacy Policy.