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.
- 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.
- 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.
# 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
- 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.
- 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.
- 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.
- 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.