Atlas renames a Python symbol across the repo by running the lsp tool's findReferences operation to get the authoritative callsite list from the language server, running grep for the old name to catch the strings, docstrings, and config the type system never sees, applying the mechanical renames with edit using replaceAll where the match is unambiguous, then compiling and running pytest through bash before grepping once more to prove zero remaining hits. A rename is where naive find-and-replace does the most damage.
How does Atlas rename a Python function across an entire repository?
Atlas renames a Python symbol in 5 steps: findReferences through the lsp tool for the authoritative callsite list, grep for the old name outside the type system, edit with replaceAll for the mechanical part, pytest through bash, then a final grep proving 0 remaining hits.
The two search passes are not redundant. The lsp tool's findReferences operation asks the Python language server which callsites actually bind to this symbol, so it correctly ignores a same-named method on an unrelated class and correctly includes an import in src/api/routes.py that a sloppy regex would miss. The grep pass covers the opposite territory: a name embedded in a Django settings string, a FastAPI route decorator argument, a pyproject.toml entry point, a docstring, a pytest fixture id. Neither pass alone is sufficient in Python, where names live in both the type system and in plain strings.
Why is grep still required when the Python language server already found the references?
Atlas runs grep for the old Python name after findReferences, step 2 of the documented rename workflow, because Python resolves plenty of names at runtime from strings the language server cannot follow: a getattr call, a Django settings module path, a pyproject.toml console_scripts entry point, a Celery task name, a pytest fixture referenced by string id.
Consider renaming a constant named DEFAULT_TIMEOUT. The lsp tool's findReferences operation returns the Python imports and attribute accesses. It does not return the line in docs/configuration.md that documents DEFAULT_TIMEOUT, nor the .env.example key, nor the log message that interpolates the name for operators. Atlas greps for the old name specifically to surface those, and grep runs through ripgrep with real regex plus include and path filters, so you can scope the sweep to *.py, to docs, or to the whole tree. The grep pass is also what the final verification uses.
What does it mean when Atlas reports Found multiple matches for oldString?
Found multiple matches for oldString is Atlas's edit tool refusing an ambiguous Python rename. When a single occurrence must change but the oldString appears 2 or more times in the file, edit throws rather than guessing, and you either add surrounding context to disambiguate or explicitly opt into replaceAll.
That refusal is the safety property that makes an automated Python rename trustworthy. A naive sed pass over src/services/billing.py would happily rewrite both the function definition you meant and the unrelated local variable that shares its prefix. Atlas edit will not. Where the match is genuinely unambiguous across the file, Atlas passes replaceAll and rewrites every occurrence in one call. Where it is not, the tool errors, and an unintended match becomes a visible failure instead of a silent corruption you discover three weeks later in a Django admin view.
How do you verify a Python rename actually finished?
Atlas verifies a Python rename with two proofs: run the suite with pytest through the bash tool and confirm it is green, then grep once more for the old name and confirm zero hits. A rename with 1 remaining grep hit is not a finished rename.
The pytest run catches the semantic half. If a callsite in src/models/invoice.py still imports the old name, the import fails and pytest reports a collection error rather than a silent pass. The final grep catches the half pytest cannot see: the docstring, the README, the pyproject.toml entry point, the comment. Atlas runs both, and because bash is a real shell, it can also run ruff format over the touched files so the rename does not leave the diff with line-length churn that obscures what actually changed.
How does Atlas keep a repo-wide Python rename reviewable?
Atlas computes a unified diff for every file edit and surfaces it for approval before writing, and every Atlas tool call is permission-gated against allow, ask, and deny rules before it runs. A rename touching 30 Python files arrives as 30 reviewable diffs, not one opaque write.
Atlas also snapshots file changes as git patches, so a rename that turns out to have caught a false positive can be diffed and rolled back rather than manually reverted file by file. For a large sweep, Atlas can draft the plan in a read-only plan agent first and ask before switching to a build agent, which means you approve the reference list and the strategy before any edit call is made. Atlas reads git branches, status, and diffs, so it can also stage the rename and create the commit once pytest is green.
Can Atlas find the Python symbol if I only half remember its name?
Atlas searches Python code with 2 retrieval methods, semantic and keyword, fused by reciprocal rank fusion, and indexes code by AST declarations using tree-sitter rather than blind line windows. A half-remembered name still lands on the right declaration in src/, not on a fragment of one.
That matters before the rename begins, when you know the behavior but not the exact identifier. Atlas retrieves the declaration itself, a whole def or class, because the index is built from tree-sitter AST nodes rather than fixed-size chunks. Once you have confirmed the symbol, the lsp tool's findReferences operation takes over and the rename proceeds against a real reference set. If your Python code cannot leave the machine, Atlas can build the same index with local Ollama embeddings.
Step by step
- 01Run atlas in a repo with a pyproject.toml or requirements.txt and let Atlas read your package layout, virtualenv, and installed dependencies.
- 02Run the lsp tool's findReferences operation on the Python symbol to get the authoritative callsite list from the language server.
- 03Run grep for the old name to catch occurrences outside the type system: docstrings, log strings, docs/, .env.example, and pyproject.toml entry points.
- 04Apply the mechanical renames with edit using replaceAll where the match is unambiguous per file.
- 05Where a single occurrence must change, expect edit to throw Found multiple matches for oldString unless you add context or opt into replaceAll.
- 06Run pytest through the bash tool and confirm the suite is green, including that no module fails to import the renamed symbol.
- 07Run ruff format over the touched Python files so the rename diff is not polluted by formatting churn.
- 08Grep once more for the old name and confirm zero remaining hits, then let Atlas stage and commit the rename.
Frequently asked questions
- how to rename a function everywhere in a Python project safely
- Use the lsp tool's findReferences operation for the authoritative callsite list, grep for the old name to catch docstrings and config, apply renames with Atlas edit using replaceAll only where unambiguous, then run pytest and grep once more for zero hits.
- why does find and replace break Python renames
- Plain find-and-replace matches text, not symbols. It rewrites an unrelated method that happens to share the name and misses the runtime strings Python resolves dynamically. Atlas splits the job: lsp findReferences for real references, grep for strings, comments, docs, and config.
- what does Found multiple matches for oldString mean in Atlas
- The Atlas edit tool refuses an ambiguous single replacement. Add surrounding context to make the oldString unique in the file, or opt into replaceAll if every occurrence should change. The error exists so an unintended match is a failure rather than a silent corruption.
- does Atlas work with uv and pytest
- Yes. Atlas runs uv and pytest through its bash tool, which is a real shell. Start atlas in a repo with a pyproject.toml or requirements.txt and it reads your package layout, virtualenv, and installed dependencies.
- will Atlas run ruff format after renaming Python code
- Atlas can run ruff format through the bash tool over the touched files, subject to your allow, ask, and deny permission rules. Every tool call is permission-gated before it runs, so no formatter executes without your rules permitting it.
- how do I prove a Python rename is complete
- Two checks. Run pytest through bash and confirm the suite is green with no import errors, then grep the repo for the old name and confirm zero remaining hits. Atlas runs both as the final steps of the rename workflow.
- can I review each file before Atlas renames it
- Yes. Atlas computes a unified diff for every file edit and surfaces it for approval before writing. It can also draft the rename in a read-only plan agent and ask before switching to a build agent that makes edits.
Try Atlas in your terminal
The terminal-native AI coding agent. Free core, single binary.
Install AtlasRelated guides
Rename a Symbol Across the Repo with Atlas in 2026
How to rename a symbol across a repo with Atlas in 2026: findReferences gets the true reference set, grep catches strings and docs, and edit refuses ambiguous matches.
Atlas for Python in 2026
Atlas is a terminal-native AI coding agent for Python in 2026. Run it in a repo with a pyproject.toml or requirements.txt and review every diff before it lands.
Onboard to an Unfamiliar Python Codebase with Atlas in 2026
Onboard to an unfamiliar Python codebase in 2026. Atlas uses codebase_search, glob, read, and lsp to map a pyproject.toml repo without opening every module.
Document a Python Module With a README Using Atlas (2026)
Atlas writes Python docs from source, not memory: lsp documentSymbol lists the real exports, read supplies behavior, and every code sample is proven with pytest.
Migrate a Deprecated API Across Every Callsite in Python with Atlas (2026)
Move a Python codebase off a deprecated function with Atlas in 2026: enumerate callers with the lsp tool, patch each with apply_patch, and run pytest after every file.
Automate GitHub Issue and Pull Request Triage in Python with Atlas (2026)
Wire the atlas github command into a Python repo's workflow in 2026. Require MODEL in provider/model form, gate on write permission, and verify with pytest and ruff format.
Plan a Multi-File Change Before Editing in Python with Atlas in 2026
Plan a multi-file Python change before editing in 2026. Atlas's plan agent denies edit for every path except .atlas/plans/*.md, then plan_exit hands off to build.
Add a Regression Test for a Bug Fix in Python with Atlas (2026)
Red first, then green. Atlas writes a failing pytest case, proves it fails with the bash tool exit code, applies the fix with edit, and re-runs the same command.