Lesson 13 of 32
Questions About an Unfamiliar Codebase
The use of Claude Code that produces no diff at all — asking a strange codebase the questions you would otherwise save up for a senior colleague.
Every lesson so far has ended in a change to your files. This one does not produce a diff at all, and it is probably the most underrated thing Claude Code does.
You have joined a new team, or inherited a service nobody remembers writing, or opened an open-source project to fix one bug in it. There are four thousand files. The person who could explain them is in meetings until Thursday.
Ask it what you would ask a senior engineer
That is the whole technique, and it needs no special prompting. Open Claude Code in the project and ask directly, in the same words you would use with a colleague:
- How does logging work?
- How do I make a new API endpoint?
- What edge cases does the customer onboarding flow handle?
- Why does this code call
foo()instead ofbar()on line 333? - What are the key data models?
- How is authentication handled?
The reason this is better than a web search is narrow but important. A search engine knows how the framework works in general. It does not know that your repository wraps every outbound request in a retry helper that swallows one specific error, because somebody had a bad week in 2023. Claude is reading the code in front of it, so its answers are about your project rather than about the idea of a project like yours.
Broad, then narrow
The order matters more than the wording. Start wide enough to get a map, then use the map to ask better questions.
- Step 1
Overview
Ask for a tour of the codebase and the main architecture patterns. You are looking for names of things, not detail.
- Step 2
One area
Pick the part you have to work in and ask how it fits together — the files involved and how they call each other.
- Step 3
One path
Ask it to trace a single flow end to end, such as a login from the form to the database.
- Step 4
One line
Now the line-level questions are worth asking, because you know what you are looking at.
Two additions worth making early. Ask about conventions: how this project names things, where tests live, what it does differently from the framework defaults. And ask for a glossary of project-specific terms, because the words in the code are usually the words the team says in meetings, and not knowing them is what makes you slow in conversations.
What that looks like
You typed: I've just joined this project. Give me an overview of the codebase and the main architecture patterns used here.
Claude ran: Read README.md
Claude ran: Search: **/*.config.*
Claude ran: Read src/server/router.ts
Claude replied: It's a Django backend with a React front end, split into three deployables: an API, a worker for scheduled jobs, and an admin site. Requests come in through api/urls.py, are handled by view classes in api/views/, and all database access goes through service functions in core/services/ rather than the views themselves. That last part is a convention rather than something enforced.
WhyNotice what came back: names, not paragraphs of theory. Those directory names are now the vocabulary for every question you ask next.
You typed: I need to add a new endpoint. Walk me through what changes, using an existing simple endpoint as the example.
Claude ran: Read api/urls.py
Claude ran: Read api/views/tags.py
Claude ran: Read core/services/tags.py
Claude ran: Read api/tests/test_tags.py
Claude replied: Four files, following the tags endpoint: a route in api/urls.py, a view class in api/views/, a service function in core/services/, and a test in api/tests/. The view does no validation itself — there is a serialiser per endpoint in api/serializers/, and the view names it in a class attribute.
WhyIt read the tests without being asked. Tests are often the most honest documentation in a repository, because they describe behaviour that someone verified rather than behaviour someone intended.
You typed: Why does the tags view call get_tags_for_user instead of querying the model directly?
Claude ran: Run: git log -p --follow core/services/tags.py
Claude replied: The commit that introduced it says the direct query missed the archived filter in three places. The service function is the single place that filter is applied. Nothing stops you querying the model directly, so this is a convention held up by review rather than by code.
WhyThis is the answer you could not have got from the code as it stands today. The reason was in the git history, and Claude went looking there because the question was 'why', not 'what'.
Point it at the source
The general prompting rule from earlier lessons applies here in a specific form: when you know where an answer lives, say so.
"Why does this class have such an odd interface" invites speculation. "Look through this class's git history and summarise how its interface came to be" sends Claude somewhere the answer actually exists. Git history, commit messages, old pull requests and comments are the places a project stores its reasoning, and they are all reachable from the terminal.
You can also include a file directly rather than waiting for Claude to find it.
Typing @ in your prompt opens a path suggester: @src/utils/auth.js puts the
file's full contents into the conversation, and naming a directory such as
@src/components gives a listing of what is in it rather than the contents of
everything inside.
Reading is not free
Exploration is the most expensive thing you can do to a context window. Every file Claude reads to answer you stays in the conversation, and a broad "investigate our permissions system" can quietly consume tens of thousands of tokens before it says a word.
Three habits keep that under control.
Scope the question. "How does caching work" over a large repository is an invitation to read hundreds of files. "How does caching work in the API layer" is a question with an end.
Delegate the reading. Ask for a subagent — "use a subagent to investigate how our auth system handles token refresh" — and the exploration happens in a separate context window that reports back only its findings. Your session gets the summary, not the four thousand lines behind it. Subagents get a full lesson later.
Use a side channel for one-offs. For a detail you need now and never again,
/btw asks a question whose answer never enters the conversation history, so it
does not grow your context.
If you would rather Claude could not edit anything at all while you are asking
questions, start it in plan mode with claude --permission-mode plan, or press
Shift+Tab during a session to cycle into it. In plan mode Claude reads and
answers but makes no changes to your source files, which turns a question
session into something you genuinely cannot break.
Where it stops
Be clear about the limits, because they define what you still owe your colleagues.
Claude can tell you what the code does, where a feature lives, and what a function handles. It can often recover why something changed, if the reason was written into a commit message. It cannot tell you about the argument in a meeting, the customer who complained, or the migration that was abandoned halfway and never mentioned again. Intent that nobody wrote down is not in the repository.
And its answers are confident whether or not they are right. This matters less here than almost anywhere else, though, because the answers are so cheap to check: every explanation names files, and you can open one. Treat what comes back as a well-informed lead rather than a verdict, and you get most of the speed with none of the exposure.
What you have left for your colleague is now a much better question. Not "how does this work" but "the service layer looks like it exists to keep the archived filter in one place — is that still the rule, or has it drifted?" That is a thirty-second conversation instead of an hour, which is the real reason teams find this useful.
What to take away
The questions you would ask a senior engineer are questions you can ask the codebase directly, and they cost nothing but a sentence. Work from broad to narrow, so each answer tells you what to ask next, and ask about conventions and vocabulary as well as structure. Point Claude at the place an answer lives — git history for why, tests for what is actually guaranteed — and keep exploration from eating your context by scoping questions narrowly or handing them to a subagent. Every answer names files, so check the important ones; the things Claude cannot know are the things nobody wrote down.
Next: turning the questions around, and having Claude interview you before it writes a line of a larger feature.
Check yourself
5 questions · pass 4/5 to unlock Letting Claude Interview You
1.What makes codebase questions such a strong use of Claude Code?
2.You have just joined a team. Which opening question is likely to work best?
3.Claude tells you that retries are handled by a wrapper in the HTTP client. How should you treat that?
4.Why does asking Claude to investigate something with a subagent help?
5.What kind of question can Claude usually NOT answer from the code alone?
5 left to answer