Applied Intelligence
Module 9: Working with Legacy Code

Querying Codebases Effectively

The exploration advantage

Most developers spend more time reading code than writing it. Studies show ratios of 10:1 or higher. Joining a new project or maintaining legacy systems means days, sometimes weeks, of reading before productive work begins.

AI agents compress this. The 2025 Stack Overflow Developer Survey found 82% of developers report AI tools help them learn unfamiliar codebases faster. What once took weeks of archaeology tracing call chains, mapping dependencies, figuring out conventions now takes hours of directed conversation.

Speed without accuracy creates problems, though. An agent that confidently explains the wrong architecture wastes more time than one that admits uncertainty. Getting good answers requires knowing what to ask, how to ask it, and how to check the results.

The Explore-Plan-Code framework

Anthropic's engineering team formalized a three-phase methodology: Explore-Plan-Code.

Explore. Before writing any code, direct the agent to read and understand. Provide general pointers ("read the authentication files") or specific paths ("examine src/auth/middleware.ts"). Explicitly tell the agent not to write code during this phase. Context gathering, not implementation.

Plan. Once the agent understands the relevant code, request a plan. Use extended thinking triggers: "think through this approach," "think hard about edge cases," or "think carefully about the architecture." Review the plan before approving implementation.

Code. After validating the plan, give explicit approval to begin implementation. Check that the solution matches expectations as code appears.

Skip exploration and you get implementations that compile but miss the point. Skip planning and you get code that works for the happy path but fails on edge cases. The framework is simple discipline, but discipline matters.

The most expensive mistake in unfamiliar codebases: letting agents jump straight to coding. An agent that spent zero tokens exploring will confidently generate code that ignores existing patterns, duplicates functionality, and breaks conventions it never learned.

Asking questions like you would a senior engineer

When approaching an unfamiliar codebase, ask agents the same questions you would ask a senior engineer on the team. No special syntax required. No prompting tricks.

Architecture questions:

  • "How does logging work in this project?"
  • "What's the authentication flow for API requests?"
  • "How do database migrations get applied?"

Implementation guidance:

  • "How do I add a new API endpoint following existing patterns?"
  • "Where should validation logic live for this feature?"
  • "What's the testing pattern for services in this codebase?"

Code clarification:

  • "What does the async move { ... } block do on line 134 of src/handlers.rs?"
  • "Why does CustomerService inherit from both BaseService and AuditMixin?"
  • "What edge cases does PaymentProcessor.validate() handle?"

Historical context:

  • "Why does this code call legacyAuth() instead of the newer authenticate()?"
  • "What problem was this module solving when it was introduced?"
  • "Are there any known issues or TODOs related to this component?"

The agent explores the codebase to find answers. Module 2 covered the mechanics: Glob for file patterns, Grep for content search, Read for file contents, and the Explore sub-agent for complex investigations.

Guiding agents to key files

Agents do not read every file in a repository automatically. They read on demand, following their own judgment about what seems relevant. This judgment is imperfect.

Explicit guidance helps:

Read the project structure and understand the architecture before
making any changes. Look at src/Application/ to understand how we
structure commands and handlers.

Pointing agents to key files reduces wasted exploration:

The authentication system is in three files:
- src/auth/provider.ts (main auth logic)
- src/auth/middleware.ts (request handling)
- src/auth/types.ts (shared types)

Review these before answering questions about auth.

Without guidance, agents examine irrelevant files, miss critical context, and make assumptions based on incomplete information.

Using @ references for direct context

Most AI coding tools support @ symbols for explicit file inclusion. These load files into context directly no waiting for the agent to discover them through search.

Claude Code supports tab-completion for file references. Mentioning a file path directly includes its contents.

Cursor provides structured @ symbols:

  • @Files for specific files
  • @Folders for entire directories
  • @Code for functions, classes, or symbols

GitHub Copilot uses @workspace for codebase-wide questions:

  • "Where is the rate limiting logic defined? @workspace"

Direct references beat hoping the agent finds the right files. When asking about specific functionality, include the relevant files:

Using the patterns in @src/components/Button.tsx, create a new
Link component that follows the same accessibility conventions.

This eliminates ambiguity about which patterns to follow.

Question patterns that work

Some question structures produce better results than others.

Specific over general. "What does processOrder() in src/orders/processor.ts do?" beats "How do orders work?" General questions invite general answers. Specific questions force the agent to examine specific code.

Bounded scope. "Trace the data flow from the submit button click in CheckoutForm.tsx to the database write" beats "Explain the checkout process." Defining start and end points constrains the investigation.

Verification requests. "List all files that import from src/utils/auth.ts" produces verifiable output. "Explain the auth utility" produces narrative that's harder to validate.

Comparative questions. "What's the difference between AuthProvider and LegacyAuthProvider?" forces the agent to examine both implementations and identify meaningful distinctions.

Assumption testing. "Does the codebase ever call processPayment() without first calling validatePayment()?" checks specific invariants rather than requesting general descriptions.

Question patterns that fail

Some patterns reliably produce poor results.

Overly broad questions. "Explain this codebase" or "How does everything work?" gets you superficial overviews that miss important details. Large codebases cannot be explained in a single response.

Questions without anchors. "Where is the bug?" without specifying symptoms or affected behavior forces the agent to guess. Provide error messages, failing test cases, or specific observed behavior.

Ambiguous references. "Fix the authentication issue" assumes the agent knows which issue among potentially many. "The /login endpoint returns 401 even with valid credentials when..." provides actionable specificity.

Questions that require human judgment. "Is this code good?" or "Should we refactor this?" require context the agent lacks. "Does this code follow the patterns established in the rest of the codebase?" is answerable. Quality assessments need human judgment about priorities and tradeoffs.

The verification imperative

Agents produce confident answers regardless of accuracy. The same fluent explanation style appears whether the agent understood the code correctly or misinterpreted it entirely.

Verification strategies:

Cross-reference claims. When an agent explains that "this function is called from three places," ask it to list those places. Claims that cannot be substantiated are often wrong.

Test against the code. If an agent explains control flow, mentally trace that flow through the actual code. Mismatches reveal misunderstandings.

Ask for evidence. "Show me the line where this configuration gets loaded" produces verifiable output. Agents that understood the code can provide evidence. Agents that guessed cannot.

Use multiple queries. Ask the same question differently and compare answers. Consistent answers suggest the agent understood correctly. Contradictions reveal uncertainty the agent didn't express.

When an agent's explanation doesn't match what you see in the code, the agent is wrong. Code is ground truth. Confidence means nothing against contradicting evidence in the actual implementation.

Sub-agents for complex investigations

Module 2 introduced the Explore sub-agent. For complex codebase questions, this architecture becomes essential.

Each sub-agent operates with fresh context it doesn't inherit the main conversation's history. After investigating, it returns a summary. The main agent gets distilled findings rather than raw search results.

This prevents context pollution. A sub-agent exploring twenty files to answer a question doesn't fill the main context with file contents. Only the conclusion propagates.

For multi-part investigations, request parallel sub-agents:

Explore the codebase using 4 tasks in parallel. Each agent should
investigate a different system:
1. Authentication and authorization
2. Database access patterns
3. API endpoint structure
4. Background job processing

Each sub-agent gets its own 200k context window. Parallelism accelerates exploration without sacrificing depth.

Building context progressively

Effective codebase querying rarely happens in a single exchange. Understanding builds through iteration.

Start broad, then narrow. Begin with architectural questions: "What are the main components of this system?" Use the answers to identify areas that need deeper investigation. Drill into specifics: "How does the event bus component handle message ordering?"

Let answers inform questions. Initial exploration reveals the codebase's vocabulary the names of services, the patterns in use, the conventions followed. Subsequent questions can use this vocabulary precisely.

Maintain continuity. Reference previous findings: "You mentioned the EventDispatcher class earlier. How does it handle failures?" Continuity reduces redundant exploration and keeps the conversation focused.

Know when to reset. If the conversation becomes confused or context fills with irrelevant information, start fresh. A clean context sometimes produces better results than accumulated history.

From understanding to action

Querying codebases effectively is the foundation for the rest of this module. Agents cannot help modify unfamiliar code until they understand it. They cannot generate documentation until they comprehend what they're documenting.

The Explore-Plan-Code framework ensures understanding precedes action. Targeted questions extract specific information. Verification catches errors before they compound.

The pages ahead build on this: mental models through extended dialogue, systematic architecture mapping, and extracting undocumented conventions from code patterns.

On this page