Skip to content

Operation contracts

All operations target Python top-level classes, functions and assignments. They do not rename a method independently or prove runtime equivalence. Use an explicit workspace root that contains source, destination and callers.

Choosing an operation

Operation Destination Preview Cycle enforcement
anvil_move / move_symbols Existing readable Python file dry_run=True; check=True also previews Normal apply and check=True; plain dry-run does not raise on a detected new cycle
anvil_extract / extract_symbols Creates missing file and parent directories; also accepts an existing target without a requested-name collision Creates then cleans up a temporary scaffold if needed Normal apply uses the move pipeline; no check option
anvil_rename / rename_symbols Same defining module dry_run=True No move-cycle check

Extraction does not create package __init__.py files. Choose an importable destination. An existing definition with a requested name blocks move/extract; rename also rejects a destination name already defined. strict=False skips absent names with warnings. An all-absent move or rename is a successful no-op; an all-absent extract apply can leave an empty new target.

Tool inputs

Tools resolve relative file paths against path (default .); absolute paths remain absolute. path is a discovery root, not a sandbox: move can re-anchor its write root to a common ancestor for endpoints outside it. Core move_symbols and extract_symbols instead consume file paths relative to the process working directory; workspace_root controls discovery/writes, not file-path resolution.

Move/extract accept CSV symbols, JSON-string rename, shared_helpers="duplicate", shared_helpers_module=None, strict=False, insert_after=None, include_helpers=True, side_effect_decorators=None. Only move accepts reexport=False and check=False. Rename accepts file, old and new, or JSON-string mapping; mapping takes precedence and its keys/values are converted to strings. Use valid, unique Python identifiers.

shared_helpers="error" rejects shared helpers. "extract" and any non-None shared_helpers_module raise NotImplementedError: the parameter exists but the strategy is not implemented. reexport=True is incompatible with a non-None rename mapping, including {}. Unsupported kwargs are accepted by the tool wrappers but ignored; do not infer support from a successful call.

ToolResult and plans

Check ToolResult.success before reading data. Failures normally carry error; warnings do not set success to false. The generic AXM CLI prints data with --json-output, rather than the full ToolResult envelope. Compact text is a summary, not a diff.

Data field Move / extract Rename
moved List of {"symbol": "OriginalName"}; names precede in-flight renaming Absent
renamed Absent List of {"old": "Old", "new": "New"}
dependencies_copied imports and constants lists Absent
callers_updated Records with file, line, old, new Same keys, line=0, old/new hold the same module name
warnings List of messages List of messages
shared_helpers_detected Records: name, used_by_moved, used_by_remaining Absent
files_modified Source and target, plus caller records for move only Defining module plus caller paths

files_modified is populated during preview too, so it is not proof of a write. Move may mix absolute endpoint paths with relative caller paths and repeat a caller. Extract currently omits rewritten callers from this field: inspect callers_updated and the actual diff as well. Move adds reexport: true or check: true only when enabled.

The Python MovePlan dataclass contains source_text_new, target_text_new, moved_names, imports_added, constants_added, warnings, shared_helpers_detected and callers_updated. It has no files_modified. Texts describe the plan before Ruff post-processing. RenamePlan contains source_text_new, renamed (a dict), callers_updated, warnings and files_modified. Neither is a Pydantic model; neither is a reusable apply token.

Errors

Core functions raise exceptions. The tools convert exceptions from the core to failure results; argument normalization occurs before the move/extract try block, so direct Python callers should still handle exceptions. The dedicated CLI exits 1 on a failed ToolResult, prints the error to stderr, and prints successful text to stdout.

Root-exported exception Meaning
SymbolNotFoundError Missing requested top-level symbol with strict mode
SymbolAlreadyExistsError Requested or renamed destination collides
ImportCycleError A newly introduced import cycle is rejected
SharedHelpersError Shared helper under the error strategy
MoveValidationError Invalid transformed Python
MovePathError Source and target have no usable common base
OverloadPartialMoveError Overload-group error type; ordinary moves expand companions together

These types are part of the exported API, not a claim that every path uses each type. Missing files can raise FileNotFoundError; unsupported options can raise ValueError or NotImplementedError; a failed batch raises RuntimeError. See write and semantic limits before interpreting success.