Automated migration codemod from Brownie to ApeWorx Ape. 17-pass deterministic transform built on Codemod's jssg engine. Validated on 5 real OSS Brownie projects (incl. Yearn Finance) with zero false positives.
# Run on any Brownie project (~3 seconds end-to-end after first invocation)
npx codemod@latest @pugarhuda/brownie-to-ape -t /path/to/your/brownie/project
# Or via direct workflow URL:
npx codemod@latest workflow run \
-w https://github.com/PugarHuda/brownie-to-ape \
--target /path/to/your/brownie/project \
--no-interactive --allow-dirty
Or:
bash
# Try the bundled demo on a public repo:
git clone https://github.com/PugarHuda/brownie-to-ape && cd brownie-to-ape
bash demo/run-demo.sh
📋 Hackathon evaluator? See EVALUATOR.md for the
3-step evaluation walkthrough (~15–20 min total): codemod run → AI
cleanup → ape compile && ape test verification. End-to-end AI-step
walkthrough on token-mix: demo/ai-step-demo.md.
Engineering tradeoffs / deferred features: docs/DEFERRED_FEATURES.md.
Why use this
Brownie was deprecated in 2023; ApeWorX Ape is the recommended successor. A typical Brownie test suite contains 50–200 mechanical pattern rewrites: every Contract.deploy(…, {"from": acct}) becomes Contract.deploy(…, sender=acct), every network.show_active() becomes networks.active_provider.network.name, etc.
# Install Codemod CLI (one-time)
npm i -g codemod
# Run on your Brownie repo
codemod run brownie-to-ape -t /path/to/your/brownie/project
# Or run from this directory locally
cd brownie-to-ape
codemod workflow run -w workflow.yaml -t /path/to/your/brownie/project --no-interactive --allow-dirty
Validated on real OSS repos
Tested on five Brownie OSS projects covering different shapes (token tutorial, oracle deploy, multi-network lottery with VRF mocks, Aave DeFi integration, Yearn Finance strategy template):
The codemod is engineered to never make incorrect changes. Key guards:
File-level marker — transforms only run on files that contain the substring brownie. Files with unrelated {"from": x} patterns (email APIs, regular dicts) are untouched.
Tx-dict whitelist — a dict literal is treated as a Brownie tx-dict only if every key is in {"from", "value", "gas", "gas_limit", "gas_price", "max_fee", "priority_fee", "nonce", "required_confs", "allow_revert"} AND "from" is present.
Contract-name heuristic — uppercase names that aren't built-in Brownie module names (accounts, network, chain, config, project) are assumed to be contract artifacts and dropped from imports with a TODO comment.
brownie.network not auto-renamed — only the specific brownie.network.show_active() pattern is rewritten (to the specific Ape equivalent). Other brownie.network.* is left for manual review since Ape exposes them differently.
Replace dict node, not arg list — preserves edits to surrounding positional args (e.g. brownie.accounts[0] inside the same call gets renamed independently).
Wildcard from brownie import * skipped — too risky to rewrite without symbol tracking.
What's NOT auto-migrated (intentionally)
These patterns are flagged with # TODO(brownie-to-ape): … for manual review or AI-assisted follow-up. They are by design left manual to keep FP at zero.
Contract artifacts (Token, FundMe, etc.) — Ape uses project.<ContractName> access. The codemod can't infer the project structure.
MockV3Aggregator[-1] style — Brownie's "last deployed" subscript. Ape uses project.<Name>.deployments[-1].
accounts.add(private_key) — Ape requires accounts.import_account_from_private_key(alias, passphrase, key).
chain.sleep(N) in expressions — Only the statement form is auto-migrated. result = chain.sleep(N) (rare — Brownie returns None) is left alone since the rewrite would change semantics.
chain.mine(N, timedelta) — Brownie's two-arg form. Skipped (only single positional N is migrated to num_blocks=N).
brownie.exceptions.VirtualMachineError — class names differ in ape.exceptions.
brownie-config.yaml → ape-config.yaml — YAML config schema migration is out of jssg scope; needs a separate transform.
If a codemod run produces something unexpected, every change is in your
target repo's working tree:
bash
cd /path/to/your/brownie/project
git checkout -- '*.py' # discard all .py changes
The codemod never touches files outside --target and never overwrites
untracked files (the YAML helper renames legacy → .legacy).
Demo cast
A pre-recorded asciinema cast at demo/demo.cast
(asciicast v2, 44 events, ~14s). Play locally:
bash
asciinema play demo/demo.cast
FAQ
Q: Will running this break my codebase?
A: No. Every change is in your working tree until you git commit. If
the diff looks wrong, run git checkout -- '*.py' to discard. The
codemod is engineered for zero false positives — validated on 4 OSS
repos.
Q: I don't trust it. Can I preview first?
A: Yes. bash scripts/preview.sh /path/to/your/project runs in dry-run
mode and prints a per-file edit summary without modifying anything.
Or use --dry-run directly with codemod workflow run.
Q: My project uses Brownie + web3.py heavily. Will this migrate
web3.py too?
A: Partially. Web3.toWei(...) and Web3.fromWei(...) get inline
TODO comments pointing to Ape's convert(...). Other web3.py patterns
(web3.eth.X) are untouched — they're a different framework upgrade
(web3.py v6 → v7)
that warrants its own codemod.
Q: How long does manual cleanup take after the codemod?
A: Most projects: 5–30 minutes. The remaining work is ~5–20% of the
migration: replace contract artifact references with project.<Name>,
configure accounts via ape accounts import, run ape compile and
fix any compile errors. The codemod's TODO comments mark every spot
that needs attention.
Q: Do I have to use the bundled YAML config converter?
A: Optional but recommended. python scripts/migrate_config.py .
translates brownie-config.yaml to ape-config.yaml for known
fields. If you'd rather convert the YAML manually, just don't run it
— the codemod doesn't depend on it.
Q: Why is my first run so slow?
A: npx downloads the Codemod CLI on first invocation (~10–20s).
Subsequent runs are ~3 seconds. Install once with npm i -g codemod
to skip this.
Q: I have feature X (Curve / Yearn / etc.) in my Brownie repo. Will
it work?
A: The codemod only transforms Brownie SDK patterns — it doesn't
touch protocol-specific code. Validated repos already cover token
contracts, fund-me oracles, lottery + VRF, and Aave DeFi integration.
If you hit a Brownie pattern that isn't migrated, file a feature
request.
Troubleshooting
Symptom:codemod: command not found
Use npx codemod@latest … (no global install needed).
Or install once: npm i -g codemod.
Symptom:codemod runs but no files change.
The target may not be a Brownie project — only files containing the
substring brownie are processed.
Run bash scripts/preview.sh <target> to see whether anything is
detected.
Symptom:from ape import … line is missing some name.
The codemod intentionally drops names that have no direct Ape
equivalent (contract artifacts, Wei, interface, etc.). Look for # TODO(brownie-to-ape): comments above the rewritten import.
Symptom:ape compile fails with NameError: contract not defined.
Brownie auto-injects contract artifacts into every namespace; Ape
doesn't. Replace MyContract.deploy(...) with project.MyContract.deploy(...). The codemod's TODO comment marks
these.
Symptom:pytest fails with
text
AttributeError: module 'ape.exceptions' has no attribute 'X'
.
The codemod maps VirtualMachineError → ContractLogicError and a
few others, but unknown exception names need manual lookup. Check
the Ape exceptions docs.
Symptom: Output has duplicate from ape.utils import convert.
Bug — file an issue. The dedup check (Pass 9) should catch this.
Symptom: Codemod CLI hangs in CI.
Pass --no-interactive --allow-dirty flags. The CLI prompts for
confirmation by default if the target isn't a clean git tree.