ChangePilot is a version-aware migration workbench for Python projects. It finds API usage that crosses a dependency upgrade boundary, traces the affected local call graph, stages conservative edits, and rejects patches that change code outside the declared rewrite set.
The repository contains two working surfaces:
- An interactive web workbench for exploring the migration flow
- A Python AST engine and command line interface for repository analysis
ChangePilot is an early engineering prototype. It is useful for inspecting a focused upgrade and testing migration contracts. It is not a replacement for a project test suite or a general Python refactoring platform.
Given a source tree and a set of current and target dependency versions, ChangePilot performs four steps:
- It selects API changes whose version boundary is crossed by the upgrade
- It locates matching call sites with Python AST analysis
- It follows reverse local calls to estimate the review surface
- It applies only deterministic edits and verifies a closed patch contract
Rules that need context-sensitive restructuring stay in the review queue. For example, a method rename can be safe enough for an automatic edit while a call shape rewrite remains manual.
npm ci
npm run devOpen the local URL printed by the development server. The sample workspace includes Pydantic and NumPy migration findings, a line-level patch preview, and contract verification.
The browser workbench uses a lightweight source detector so it can run without a backend. The Python package is the reference implementation for AST-based analysis.
ChangePilot requires Python 3.11 or newer and has no runtime dependencies.
python -m venv .venv
# Linux and macOS
source .venv/bin/activate
# Windows PowerShell
.venv\Scripts\Activate.ps1
python -m pip install -e .Scan the included example:
changepilot scan examples/release_service.py \
--from pydantic=1.10.14 \
--from numpy=1.26.4 \
--to pydantic=2.7.4 \
--to numpy=2.0.0Expected output:
Scanned 1 files and 28 lines. Found 3 migration call sites.
examples/release_service.py:12:12 LOW BaseModel.parse_obj -> BaseModel.model_validate
examples/release_service.py:16:12 LOW BaseModel.dict -> BaseModel.model_dump
examples/release_service.py:20:37 LOW numpy.float_ -> numpy.float64
Preview the safe patch:
changepilot migrate examples/release_service.py \
--from pydantic=1.10.14 \
--from numpy=1.26.4 \
--to pydantic=2.7.4 \
--to numpy=2.0.0Add --write only after reviewing the diff.
flowchart LR
A["Current and target versions"] --> B["Version path resolver"]
C["Python source tree"] --> D["AST index"]
B --> E["Applicable change rules"]
D --> F["Call-site matcher"]
E --> F
F --> G["Reverse call impact graph"]
G --> H["Safe patch set"]
G --> I["Manual review queue"]
H --> J["Closed patch contract"]
J --> K["Verified diff"]
The core modules have narrow responsibilities:
| Module | Responsibility |
|---|---|
catalog.py |
Stores API change records and selects rules for a version path |
analyzer.py |
Builds AST indexes, matches call sites, and traces reverse callers |
migrate.py |
Applies the subset of rules marked as deterministic |
evaluation.py |
Verifies patch boundaries and entity state changes |
benchmark.py |
Runs labeled positive and negative regression fixtures |
cli.py |
Exposes scan, migrate, and benchmark commands |
See Architecture for the data contracts and failure boundaries.
The starter catalog contains seven rules across Pydantic, NumPy, pandas, and Flask.
| Library | Change | Action |
|---|---|---|
| Pydantic | BaseModel.dict to BaseModel.model_dump |
Automatic |
| Pydantic | BaseModel.json to BaseModel.model_dump_json |
Automatic |
| Pydantic | BaseModel.parse_obj to BaseModel.model_validate |
Automatic |
| NumPy | numpy.float_ to numpy.float64 |
Automatic |
| NumPy | numpy.complex_ to numpy.complex128 |
Automatic |
| pandas | DataFrame.append to pandas.concat |
Manual review |
| Flask | Remove the JSON helper app keyword |
Manual review |
Each rule records a version boundary, match target, replacement, risk level, confidence, edit policy, and upstream documentation URL. A rule is active only when the requested upgrade crosses its boundary.
The catalog is intentionally small. Adding hundreds of weak rules would make the interface look complete while reducing trust in the patch set. See Rule authoring for the acceptance checklist.
Automatic edits are evaluated under a closed patch boundary.
A patch passes when:
- The migrated source parses as Python
- All automatically fixable findings are cleared
- Every changed line maps to an automatic rule
- Lines with manual findings remain unchanged
The state evaluator also supports added, deleted, and updated entity assertions. Any state change that is not explained by an assertion causes verification to fail.
This outcome-based check is useful for testing migration runners and agent workflows. It does not execute untrusted source code.
Run the regression benchmark:
changepilot benchmark --output results/baseline.jsonThe checked-in baseline covers 11 labeled fixtures:
- Five exact automatic patch cases
- Two manual review cases
- Four negative or boundary cases
The current fixture result is:
| Metric | Result |
|---|---|
| Detection precision | 1.0000 |
| Detection recall | 1.0000 |
| Detection F1 | 1.0000 |
| Exact patch rate | 1.0000 |
| Contract pass rate | 1.0000 |
These values describe only the small repository fixture set. They are regression signals, not evidence of broad performance on arbitrary projects.
# Python unit and contract tests
python -m unittest discover -s python/tests -v
# Python lint and formatting checks
python -m ruff check python/src python/tests examples
python -m ruff format --check python/src python/tests examples
# Web build and rendered output tests
npm test
# TypeScript and React lint
npm run lintThe Python suite currently contains 25 tests covering:
- Version boundary selection
- Import alias resolution
- Typed Pydantic receiver detection
- NumPy namespace changes
- pandas review routing
- Reverse caller tracing
- Syntax error handling
- Safe rewrite idempotence
- Closed patch rejection
- Entity state diff assertions
- Benchmark metric generation
GitHub Actions runs the Python and web suites independently.
app/ Interactive workbench
src/engine/ Browser analysis model
python/src/changepilot/ Python AST engine and CLI
python/tests/ Unit and contract tests
examples/ Small original migration example
results/baseline.json Reproducible fixture benchmark output
docs/ Architecture and rule authoring notes
.github/workflows/ Continuous integration
The first release does not call an LLM. Every automatic edit must be explainable by a catalog rule and testable with an exact contract. A future model-backed planner can propose candidates, but it should not weaken the verification boundary.
A deprecated symbol is not automatically relevant. The current version must be below the recorded change boundary and the target version must reach or cross it.
Confidence helps prioritize findings. The auto_fix field controls mutation authority. A high-confidence match can still require manual review when the replacement changes call structure.
The scanner parses source and inspects syntax trees. It does not import or run the analyzed repository. This keeps scans deterministic and avoids triggering project side effects.
- The catalog is small and manually reviewed
- Cross-file type and data flow inference are not implemented
- The reverse call graph covers direct local function names
- Method receiver inference is deliberately conservative
- The browser detector is less precise than the Python AST engine
- Safe rewrites operate at line granularity
- Python syntax validation does not prove runtime compatibility
This repository contains an independent implementation and original fixtures.
It does not include third-party papers, research datasets, benchmark traces, source archives, or copied project assets. The checked-in metrics are produced only from fixtures in this repository. The project does not claim reproduction or authorship of external results.
API migration facts are linked to the official upstream documentation embedded in each catalog rule. The rule catalog is engineering metadata, not a claim of ownership over the underlying libraries or their release notes.
Read CONTRIBUTING.md before proposing a new rule. Every automatic rule needs a version boundary, a positive fixture, a negative fixture, an idempotence test, and an upstream documentation link.
ChangePilot does not execute scanned source code. Report security issues through the process in SECURITY.md.
ChangePilot is available under the MIT License.