How to Use a Coding Tool Like an Expert
When executing multi-file refactors, I manage, restrict, and structure my local codebase context using a strict hierarchical filtering system designed to maximize accuracy and minimize token waste.
Here is exactly how I structure and execute that process:
1. Discovery and Map Generation
Before reading or editing any files, I construct an abstract map of the codebase. I do not pull full source code at this stage.
- Directory Trees: I run a shallow directory listing to understand the project's layout.
- Symbols and Signatures: I search for class definitions, method signatures, and export statements across the target modules.
- Dependency Graphs: I map out how the target files import one another to identify the upstream and downstream impacts of the refactor.
2. Context Restriction (The "Need-to-Know" Filter)
To prevent token bloat and LLM confusion, I categorize files into three strict isolation zones:
- The Edit Zone: These are the exact files that require code modifications. I ingest these files completely.
- The Reference Zone: These are files that interact directly with the Edit Zone (e.g., types, interfaces, or parent classes). I only ingest their structural definitions, type signatures, or relevant snippets—never the full implementation.
- The Noise Zone: Implementation details of unrelated modules, external dependencies, and build artifacts. These are completely blocked from my context.
3. Structured Multi-File Ingestion
When I load the required files into my active context window, I enforce a clean XML/Markdown boundary structure. This structure prevents me from blending different files together or hallucinating missing links:
4. Fragmented Execution (Avoiding the "All-at-Once" Trap)
Instead of rewriting five files in a single pass—which drastically increases the risk of hallucinations—I execute refactors sequentially using a strict state machine:
- Plan: I generate a plaintext implementation plan outlining the exact order of changes.
- Modify: I apply changes to one file at a time, starting from the lowest dependency (e.g., types first, then core logic, then entry points).
- Verify: After each file modification, I review the updated file against the rest of the context to ensure type safety and logic consistency before moving to the next file.
To see how this works in practice, here is a concrete example of a multi-file refactor where Claude utilizes custom tool skills, MCP (Model Context Protocol) servers, GitLab, and Jira to update a Python user authentication system.
The Scenario
Jira Ticket (AUTH-42): Migrating a legacy Python codebase from custom dictionary-based user sessions to structured
Pydantic models across a service layer, a route layer, and tests.Step 1: Discovery & Map Generation
Claude receives the Jira ticket via an MCP Jira Server connection. Before reading any code, Claude invokes a custom codebase-indexer skill (via a local Filesystem/Git MCP server) to map the directory.
- Tool Call:
mcp__filesystem__list_directory(path="./src") - Tool Call:
mcp__grep__search(pattern="def login") - Output Matrix: Claude maps out that
auth.pyimportsuser_service.py, which in turn relies onschemas.py.main.pyinitializes the app but does not manipulate user dictionaries directly.
Step 2: Context Restriction
Claude explicitly partitions the project files into the three strict isolation zones, dropping everything else to save tokens.
- Edit Zone (Full Ingestion):
schemas.py,user_service.py,auth.py,test_auth.py. - Reference Zone (Signatures Only):
main.py(Claude uses an MCP tool to fetch only the top 10 lines showing how the app starts, ignoring the database configuration logic below it). - Noise Zone (Blocked): Dockerfiles, CI/CD configuration files, and unrelated business logic folders.
Step 3: Structured Multi-File Ingestion
Claude pulls the Edit Zone files into the active context window, isolating them cleanly inside explicit structural tags so the code logic never bleeds together.
Step 4: Fragmented Execution & Workflow Integration
Instead of outputting all changes at once, Claude executes a sequential state machine, executing terminal commands and Git operations via MCP at each milestone.
- Modify Lowest Dependency (
schemas.py): Claude overwrites the file to use Pydantic.- Tool Call:
mcp__filesystem__write_file(path="src/schemas.py", text="from pydantic import BaseModel\nclass UserSession(BaseModel):\n id: int\n role: str")
- Tool Call:
- Modify Middle Layer (
user_service.py): Claude adjusts the service layer to instantiate the new Pydantic model. - Modify Top Layer & Tests (
auth.py&test_auth.py): Claude updates the endpoints and rewrites the test assertions from dictionary lookups (session['id']) to object attributes (session.id). - Automated Verification: Claude runs pytest via the terminal MCP server to ensure type safety and logic integrity.
- Tool Call:
mcp__terminal__execute_command(command="poetry run pytest")
- Tool Call:
- GitLab & Jira Update: Once tests pass 100%, Claude uses the GitLab MCP Server to create a branch, commit the changes, and push a Merge Request, concluding by updating the Jira ticket status.
- Tool Call:
mcp__gitlab__create_merge_request(branch="feature/AUTH-42-pydantic-migration", title="Refactor sessions to Pydantic") - Tool Call:
mcp__jira__update_issue(ticket_id="AUTH-42", status="In Review", comment="Refactor complete. MR opened in GitLab.")
- Tool Call:
Here is the exact setup and configuration guide to bind Claude Desktop / Claude Code to your workflow using the official and community-standard MCP (Model Context Protocol) servers, paired with a robust Python verification stack.
Part 1: Initializing & Configuring MCP Servers
MCP configurations are stored centrally in a JSON file. If you are using Claude Desktop, this file is located at:
- Mac/Linux:
~/.claude/mcp.json - Windows:
%APPDATA%\Claude\mcp.json
Add the following standard configurations to your
mcp.json to link Claude to your system:Step-by-Step Initialization:
- GitLab Setup: The official GitLab MCP Server uses an elegant HTTP OAuth 2.0 transport flow. When Claude starts for the first time, your web browser will automatically open to securely authorize the connection directly to your GitLab account. [1]
- Jira Setup: Generate a Jira API token inside your Atlassian Account Settings under Security. Paste that token into the
JIRA_API_TOKENenvironment variable in the JSON configuration above. [2, 3] - Restart Claude: Fully quit and restart Claude Desktop (or relaunch your terminal if using Claude Code via
/mcp) to activate the connections. [1, 4]
Part 2: The Python Verification Stack (Pre-Push Checks)
To guarantee that Claude does not push broken code, it must use a local execution environment to test code variations before opening a GitLab Merge Request. Integrate these three core tools via your build pipeline (e.g., inside a
pyproject.toml using poetry or pipenv):| Tool | Verification Role | Claude Execution Command |
|---|---|---|
ruff | Linting & Code Style: Instantly catches syntax errors, unused imports, or bad formatting across edited files without executing code. | poetry run ruff check src/ |
mypy | Static Type Checking: Vital when refactoring interfaces (like dictionaries to Pydantic). Catches type conflicts upstream or downstream. | poetry run mypy src/ |
pytest | Functional Unit Testing: Executes unit tests to verify behavior and ensure that updated code matches expected outputs. | poetry run pytest |
Part 3: The Complete Automated Workflow
Once everything is wired together, a typical interaction loop handles the entire task seamlessly from start to finish: