
bargo
A developer-friendly CLI for Noir development
About
The problem it solves Noir developers have been stuck juggling three separate CLIs— nargo (Rust), bb (C++), and garaga (Python)—each with its own flags, file-name conventions, and hidden traps. 1. Cognitive overload - Memorising dozens of flags per step (-b, -w, -o, --oracle_hash keccak, --zk, …). - Manually typing long, error-prone paths ( target/<pkg>.json, target/<pkg>.gz, …) even though the tools themselves created those files. - Switching mental context between three binaries just to finish a single proof pipeline. > A simple “compile → prove → verify” flow could balloon into 7–10 commands and 200+ characters of flags. 2. Inconsistent workflows & toolchains - EVM vs Starknet required two completely different ecosystems (Foundry vs Scarb) with no shared state. - Developers often forgot to pass Keccak vs Poseidon hashes, leading to proofs that didn’t match their verifier contracts. - Class hashes / contract addresses had to be copied by hand from one command’s stdout into the next—easy to make mistakes. How bargo fixes it: - One opinionated CLI (bargo …) that wraps all three tools with sane defaults and colour-coded guidance. - End-to-end commands (bargo prove, bargo cairo gen, bargo evm deploy) that chain all necessary sub-steps safely and atomically. - Path intelligence – auto-detects package name from Nargo.toml, isolates artifacts into target/bb/ and target/starknet/, and never asks you to re-type a file it just created. - Automatic state management – class hashes, contract addresses, calldata files are stored and reused so you never copy-paste hex again. - Honest error reporting – colourful ✓ / ✗ banners, with actionable hints instead of silent failures. - Parity across ecosystems – Same UX whether you are targeting Solidity (Foundry) or Cairo (Scarb) for your onchain verification; both get … gen • build • deploy • verify-onchain flows. - Hack-friendly implementation – pure process-exec; no FFI rabbit holes, so contributors can jump in with only Rust knowledge. ```bash # Before (EVM + Starknet) nargo execute bb prove -b … -w … -o … --oracle_hash keccak bb write_vk -b … -o … --oracle_hash keccak garaga gen --system ultra_starknet_zk_honk --vk … … garaga calldata --proof … --vk … … garaga declare … garaga deploy … garaga verify-onchain … # After (with bargo) bargo build bargo prove bargo evm gen && bargo evm deploy && bargo evm verify-onchain # Solidity bargo cairo gen && bargo cairo deploy && bargo cairo verify-onchain # Starknet ```
How it's made
Challenges we ran into 1. Three languages, three build systems Rust (nargo), C++ (bb), and Python + Rust + Cairo (garaga) do not like sharing the same sandbox. - Problem – we kept breaking peoples’ PATHs and virtual-envs just by running tests. - Fix – treated every backend as a black-box binary. One spawn_cmd() helper abstracts away the language; CI simply installs the right binaries in $PATH. 2. Proof / VK filename collisions Both bb and Garaga insist on writing files literally named proof and vk. The first time I tried to support both EVM and Starknet we ended up overwriting artifacts. - Problem – Solidity proof quietly replaced the Starknet one; verification failed later with no clue why. - Fix – introduced backend-scoped sub-folders (target/bb/, target/starknet/) and a tiny target_dir(Flavour) helper that every wrapper calls. 3. Keccak vs Poseidon hash mismatch Generating a Solidity verifier with `--oracle_hash keccak` but a Poseidon proof gives you a contract that always fails. - Problem – easy to overlook, silently wasted an hour every demo run. - Fix – `bargo evm gen` / `prove` always regenerates the proof & VK with Keccak, even if one already exists. Warnings shout if you try to mix hashes. 4. Parsing fragile CLI output Foundry prints “Deployed to: 0x…” on one line; Garaga prints JSON; bb shoves ANSI codes into stderr. - Problem – naïve regexes broke every time we updated a tool. - Fix – surrounded each external call with --json or --silent flags when available, and wrote resilient tiny parsers that fall back to grep only if JSON missing.