Stacks

Plan a Multi-File Change Before Editing in Python with Atlas in 2026

Updated 9 min read

Atlas plans a multi-file Python change before a single line is edited by putting you in a plan agent whose description is literally Plan mode. Disallows all edit tools. The plan agent's permission set denies edit for every path except the plan markdown under .atlas/plans/*.md, so research with codebase_search, grep, read, and the lsp tool cannot turn into an edit. You design the refactor across your pyproject.toml packages, decide which pytest suites must change, then call plan_exit to switch to the build agent.

How do you plan a refactor across many Python files before editing?

Atlas plans a multi-file Python refactor in 2026 inside a plan agent whose description is Plan mode. Disallows all edit tools. The permission set denies edit for "*" and allows it only under .atlas/plans/*.md, so a design pass across your pyproject.toml packages cannot silently modify a .py module.

The job to be done is designing a change that touches many files, and getting it reviewed, before a single line is modified. In Python that usually means a rename that ripples through imports, a signature change that breaks every caller, or moving a module between packages while keeping requirements.txt intact. Atlas drafts a plan in a read-only plan agent and asks before switching to a build agent, so the whole design phase happens with edit tools structurally unavailable rather than merely discouraged. Every Atlas tool call is permission-gated against allow, ask, and deny rules before it runs, which is what makes plan mode a guarantee rather than a policy.

Which Atlas tools stay available in Python plan mode?

Atlas keeps 6 tools available in plan mode: plan_exit, codebase_search, grep, read, lsp, and question. Research with codebase_search, grep, read, and the lsp tool all stay allowed, so you can trace every caller of a Python function before you decide how to change its signature.

Planning without research is guessing. codebase_search finds the modules that implement the behavior you are about to change, even when your words never appear in the source, because Atlas indexes code by AST declarations using tree-sitter. grep confirms literal occurrences of the symbol across your .py files, including conftest.py fixtures and the pytest modules that will break. The lsp tool enumerates the callsites so the blast radius is a list rather than an estimate. The question tool lets Atlas ask you before assuming, which is exactly what you want while the design is still moving.

Where does the Atlas plan file live in a Python repo?

Atlas writes the plan into a markdown file under .atlas/plans/, the 1 path plan mode is permitted to write. The plan agent's permission set denies edit for "*" and allows only .atlas/plans/*.md, so your Python source, your pyproject.toml, and your pytest suites are untouchable until you leave plan mode.

Keeping the plan inside the repo means it is reviewable the same way code is: it lives on a branch, it shows up in a diff, and it can be commented on before anyone writes an edit. The plan file sits alongside your working tree under .atlas/plans/, so it is reviewed on the branch rather than in a scratchpad you lose. A good Python plan names the modules to touch, the imports that will move, the pytest suites that must be updated, whether uv will need a new pin, and whether ruff format will reflow any file you are about to modify.

How does plan_exit hand off to the build agent in Atlas?

Atlas ends plan mode with the plan_exit tool, which asks exactly 1 question: Plan at <path> is complete. Would you like to switch to the build agent and start implementing? Answering Yes hands off to the build agent. Answering No raises Question.RejectedError and keeps you refining the plan.

The handoff is an explicit gate, not a silent transition, which is the entire point of separating the plan agent from the build agent. Until you answer Yes, no Python file can be edited, because the plan agent's permission set denies edit for every path other than the plan markdown. After you answer Yes, the build agent implements the plan, and every edit to a .py module arrives as a diff you approve before pytest runs. Answering No is a normal outcome: Question.RejectedError simply returns you to planning with the research context intact.

How do you validate a planned Python change with pytest and ruff format?

Atlas validates a planned Python change after the plan_exit handoff by running 3 real commands. Sync with uv, run pytest to prove the suites that the plan named as at-risk actually pass, then run ruff format so the diff you review contains logic changes rather than reflowed lines.

A plan is only as good as its test story, so the plan file written under .atlas/plans/ should name which pytest suites must change and which must keep passing untouched. Once the build agent starts implementing, pytest is the arbiter, and uv keeps the virtualenv aligned with pyproject.toml so the run is reproducible. ruff format is worth running before you read the diff, because unformatted lines make a multi-file Python change harder to review than it needs to be. uv keeps the virtualenv aligned with pyproject.toml, so a failing pytest run after the handoff means the plan was wrong, not the environment.

What belongs in an Atlas plan file for a Python change?

An Atlas plan file for a Python change names 5 things: the .py modules to touch, the imports that move, the pytest suites at risk, whether uv needs a new pin in pyproject.toml, and whether ruff format will reflow a file. The plan lives under .atlas/plans/.

A Python plan that names its pytest suites is a plan that can be checked. Renaming a function in a package means every from x import y statement mentioning it must move, and conftest.py fixtures usually import the same symbol. A change that adds a dependency means uv must pin it in pyproject.toml or requirements.txt. A change that touches long lines means ruff format will reflow them and make the diff noisy. Writing all of that into the plan markdown under .atlas/plans/ before calling plan_exit is what makes the build agent's Python work reviewable.

How do you size a Python refactor before you start editing?

Sizing a Python refactor means counting 3 things while the Atlas plan agent still denies edit: the .py modules that import the symbol, the pytest suites that exercise it, and the conftest.py fixtures that construct it. grep and the lsp tool produce all 3 lists without writing a byte.

A Python rename is never local, because from x import y statements spread the symbol across packages and conftest.py fixtures usually import it too. grep through ripgrep, scoped to *.py, lists every literal occurrence. The lsp tool lists the callsites the text search cannot see, such as a Django middleware referenced by dotted string path. pytest suites that name the symbol are the definition of done. If the change adds a dependency, uv must pin it in pyproject.toml or requirements.txt, and that belongs in the plan too, before plan_exit hands the work to the build agent.

Step by step

  1. 01Switch to the Atlas plan agent; its permissions deny edit for "*" and allow it only under .atlas/plans/*.md, so your .py files are read-only.
  2. 02Research the blast radius with codebase_search, grep, read, and the lsp tool; all four stay allowed in plan mode.
  3. 03Use grep with include filters across your .py sources to list every conftest.py fixture and pytest module the change will break.
  4. 04Write the plan into the allowed markdown path under .atlas/plans/, naming the modules to move, the imports to update, and whether uv needs a new pin in pyproject.toml.
  5. 05Call plan_exit: it asks Plan at <path> is complete. Would you like to switch to the build agent and start implementing?
  6. 06Answer Yes to hand off to the build agent, or answer No to raise Question.RejectedError and keep refining the Python plan.
  7. 07After the build agent implements, sync with uv and run pytest to prove the suites the plan named still pass.
  8. 08Run ruff format, then review the unified diff Atlas surfaces for every file edit before it writes.

Frequently asked questions

how do I plan a large Python refactor with an AI agent before it edits code
Switch to the Atlas plan agent. Its permission set denies edit for "*" and allows writing only under .atlas/plans/*.md, so research with codebase_search, grep, read, and the lsp tool cannot turn into an edit of a .py file.
can I stop an AI coding agent from editing files while it researches
Yes. The Atlas plan agent is described as Plan mode. Disallows all edit tools. Every Atlas tool call is permission-gated against allow, ask, and deny rules before it runs, so the restriction is enforced, not advisory.
what is plan_exit in Atlas
plan_exit is the tool that ends plan mode. It asks Plan at <path> is complete. Would you like to switch to the build agent and start implementing? Yes hands off to the build agent, and No raises Question.RejectedError.
where does Atlas save its plan file
Atlas writes the plan into a markdown file under .atlas/plans/, which is the only path plan mode is permitted to write. Your Python modules, pyproject.toml, and pytest suites stay untouched until you exit plan mode.
how do I find every caller before changing a Python function signature
Use the lsp tool inside plan mode to enumerate callsites, and confirm with grep across your .py files. Both tools stay allowed while edit is denied, so the blast radius is a list rather than an estimate.
how do I make sure a multi-file Python change does not break pytest
Name the at-risk pytest suites in the plan file before the plan_exit handoff, then run pytest after the build agent implements. uv keeps the virtualenv aligned with pyproject.toml so the run is reproducible.
can I undo an AI agent's Python edits if the plan was wrong
Yes. Atlas snapshots file changes as git patches so edits can be diffed and rolled back, and it computes a unified diff for every file edit and surfaces it for approval before writing.

Try Atlas in your terminal

The terminal-native AI coding agent. Free core, single binary.

Install Atlas

Related guides

Plan a Multi-File Change Before Editing with Atlas in 2026

How to plan a multi-file change with Atlas in 2026: the plan agent denies all edit tools, you research with codebase_search and lsp, then plan_exit hands off.

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.

Audit a Python Repo with Parallel Subagents in Atlas (2026)

Audit a Python repo with parallel Atlas subagents in 2026. Slice by package, launch read-only explore tasks, and merge findings without flooding your context.

Diagnose a Hanging or Long-Running Command in Python with Atlas (2026)

Is your Python command slow or blocked on stdin? In 2026 Atlas races every bash command against a timeout and its shell_metadata tells you which, so pytest and uv stop hanging.

Extract a Shared Helper From Duplicated Code in Python with Atlas (2026)

Duplication in Python is semantic, not textual. Atlas finds near-duplicate logic with codebase_search in 2026, collapses it with apply_patch, and proves it with pytest.

Research a Third-Party API Before Integrating It in Python with Atlas in 2026

Research a third-party API before integrating it in Python in 2026. Atlas uses websearch and webfetch to pull live docs, then writes against real signatures.

Self-Review Your Working Diff Before Committing in Python With Atlas (2026)

How to self-review a Python working diff before committing with Atlas in 2026: read the whole diff, grep for leftover breakpoints, then run pytest and ruff format.

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.

Browse this resource hub