Ddmetagame

brownie-to-ape

Production-grade migration from Brownie to Ape Framework with deterministic jssg transforms + AI for edge cases. Automates 80%+ of the upgrade.

cross-migrationbrownieapepython
Public
17 executions
Run locally
npx codemod brownie-to-ape
Documentation

Tests

brownie-to-ape

Hybrid AST + AI Codemod for migrating Python Ethereum projects from
Brownie to
Ape Framework.

Brownie's README says Brownie is no longer actively maintained and points Python
Ethereum developers toward Ape Framework. brownie-to-ape turns that migration
into a repeatable Codemod workflow: seven deterministic jssg / ast-grep
transforms handle the safe majority of code changes first, then one constrained
AI step handles only documented edge cases that remain.

Real-World Result

brownie-to-ape was tested on three public Brownie repositories:

RepositoryFiles changedBrownie patterns beforeBrownie patterns afterAutomatedRemaining
smartcontractkit/chainlink-mix1977889.6%10.4%
PatrickAlphaC/brownie_simple_storage490100.0%0.0%
PatrickAlphaC/brownie_fund_me65180.0%20.0%
Combined2991990.1%9.9%

Metric basis: Brownie-specific Python/YAML signatures before and after the
workflow, excluding generated build artifacts. The measured result is 80%+
automated on real projects
, with remaining work concentrated in dynamic
wrappers, legacy web3.eth.contract(...) event filters, Brownie conversion
helpers, and project-specific exception handling.

Full run notes are in:

One-Command Usage

Run against an existing Brownie project clone:

bash

Or run directly from the registry:

bash

What It Migrates

  • Brownie imports to Ape imports
  • accounts[0], accounts.add(...), Account.from_key(...), and LocalAccount
  • Contract.at(...), Contract.from_abi(...), project contract containers, interfaces, and deploy calls
  • Brownie transaction dictionaries like {"from": account} to Ape keyword arguments such as sender=account
  • network.show_active(), network.connect(...), web3.eth.*, and chain-id patterns
  • Brownie pytest helpers, isolation fixtures, event dictionaries, brownie.reverts, and brownie.test.strategy
  • project.load(...), run(...), Click entrypoints, and Brownie script helpers
  • brownie-config.yaml / brownie-config.yml to Ape-style config

Before / After: simple_storage

From PatrickAlphaC/brownie_simple_storage:

diff

Test deployment example:

diff

Before / After: chainlink-mix

From smartcontractkit/chainlink-mix:

diff

Config migration example:

diff

How It Works

The workflow is deliberately hybrid:

  1. Deterministic transforms run first on Python and YAML files using Codemod
    jssg with ast-grep.
  2. Each deterministic transform owns a narrow migration category and avoids
    broad rewrites.
  3. A single Codemod built-in AI step runs last, after the safe mechanical
    changes are already applied.
  4. The AI step is constrained by a system prompt that requires official Ape docs,
    forbids invented APIs, preserves business logic, and leaves short
    TODO(brownie-to-ape) comments when project context is required.

Deterministic transform order:

  1. src/transforms/imports.ts
  2. src/transforms/accounts.ts
  3. src/transforms/contracts.ts
  4. src/transforms/networks.ts
  5. src/transforms/testing.ts
  6. src/transforms/project-cli.ts
  7. src/transforms/config-yaml.ts

The final AI step only handles the remaining edge cases:

  • complex custom deployment scripts
  • legacy web3.py / Brownie wrapper code
  • non-standard account and contract patterns
  • heavy pytest mocking
  • remaining deprecated Brownie APIs after deterministic transforms

See src/ai-edge-cases.md for examples of what the AI
step should and should not touch.

Screenshots / Diff Placeholders

Use these slots in the hackathon submission or Codemod Registry listing:

AssetPlaceholderCapture command
Dry-run overviewdocs/screenshots/dry-run-simple-storage.pngnpx codemod workflow run -w workflow.yaml --target /tmp/brownie-simple-storage-demo --dry-run --allow-dirty
Chainlink diff statdocs/screenshots/chainlink-mix-diff-stat.pngcd /tmp/chainlink-mix-brownie-to-ape-2 && git diff --stat
Simple Storage deploy diffdocs/screenshots/simple-storage-deploy-diff.pngcd /tmp/brownie-simple-storage-brownie-to-ape && git diff -- scripts/deploy.py
Combined metrics tabledocs/screenshots/real-repo-metrics.pngOpen real-repo-test-results.md and capture the metrics table

Demo Commands

Chainlink mix dry-run:

bash

Simple Storage dry-run and apply:

bash

Expected changes:

  • imports move from Brownie to Ape
  • deployment calls use project.ContractName.deploy(..., sender=account)
  • local accounts move toward accounts.test_accounts[index]
  • private-key loading is converted to accounts.load(...) with manual import guidance
  • network checks move from network.show_active() to networks.provider.network.name
  • Brownie config receives an Ape-style starter config
  • ambiguous dynamic wrappers remain for review instead of being guessed

Development

Install and validate:

bash

Run the workflow against fixtures:

bash

Current local validation:

text

Publishing

Validate before publishing:

bash

Publish to Codemod Registry:

bash

References

Screenshots

Dry-run diff stat

Diff stat

Deploy script migration

Deploy diff

Test file migration

Test diff

Config migration

Config diff

Why the AI step made zero edits

In the smoke tests on chainlink-mix, brownie_simple_storage, and brownie_fund_me, the AI step made zero edits. This is the intended behavior: the seven deterministic transforms were comprehensive enough to handle the safely rewritable Brownie patterns in these repos. The AI step activates only when documented Ape equivalents exist for patterns the deterministic transforms intentionally skip, such as dynamic wrappers, custom account classes, complex event dictionary usage, or legacy web3.py event filters. Its zero-edit result is a signal of deterministic coverage, not a misconfiguration.

Before

This is one example from the codemod's test cases. The codemod may handle many more cases.

Ready to contribute?

Build your own codemod and share it with the community.