rewrite
Transform code patterns project-wide by replacing matches of a Python source pattern with a goal template, with dry-run audits and match constraints.
Instructions
Rewrite every site matching a structural Pattern into a Goal, project-wide — for transformations no dedicated refactoring expresses, such as migrating a deprecated call form (${obj}.get_attribute(${key}) -> ${obj}[${key}]) or collapsing an idiom. The Pattern is Python source with ${wildcard} placeholders; the Goal is the replacement template reusing those Wildcards. Prefer a dedicated behaviour-preserving tool (rename, inline, change_signature, move, use_function) whenever one fits; use rewrite only when none does, because a Rewrite is not behaviour-preserving: you assert that Pattern and Goal are equivalent, and the tool guarantees only that it rewrites exactly the Match Sites it reports. Control over-matching with per-Wildcard Match Constraints, e.g. constraints={"obj": {"type": "myapp.models.User"}}: name / type / object / instance narrow by a symbol's dotted path (one per Wildcard), and exact: true narrows to the Wildcard's literal name. type matches instances of exactly that class; instance matches instances of its subclasses (not the base class's own) — to cover a class and its subclasses, run once with each. A constrained run reports only the sites the constraint engages (matched or unsure), not every textual match. Each Match Site reports its certainty: matched (constraints satisfied) or unsure (a constraint that cannot be established at that site, common in dynamically typed code). Unsure sites are surfaced but not rewritten, so nothing is silently skipped; add unsure: true to a Wildcard's constraints to rewrite them too — they stay flagged unsure in the result for you to audit. When the Goal introduces a name the target modules do not import, pass imports (a list of import statements, added to each changed module, deduplicated); the tool never infers imports — checking for missing names is your LSP's job, so an omitted import leaves broken code. A rewrite that would produce unparsable Python fails safely in either mode, naming the file and parse location, with nothing written. Defaults to a Dry Run that previews without writing; review every Match Site for over-matching before setting apply=true. A truncated Match Site list ('showing N of M', unsure sites first) means the audit is incomplete — tighten the Pattern or Match Constraints and preview again before a Live Run. Both modes report the file-level Blast Radius and every Match Site (file + Range in 0-based UTF-16 LSP coordinates, against the pre-apply text — live targets for your LSP on a Dry Run, audit records after a Live Run). Start from a clean git tree, since git is the reversal mechanism, and run git diff after a Live Run to verify the equivalence you asserted. Pass root (the project directory) explicitly. Keep navigation and reading with your LSP; this tool only changes code.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| goal | Yes | ||
| root | No | ||
| apply | No | ||
| imports | No | ||
| pattern | Yes | ||
| constraints | No |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
No arguments | |||