Asking a codebase questions as a workflow
By the end you can
- Use question-asking as the onboarding path into a repository you did not write
- Match the question to the source that can answer it — the code, the git history, or the docs
- Scope an investigation so it does not read hundreds of files
- Read an @ directory reference for what it actually returns
Lesson 11.1 made the tree smaller before the session started; Lesson 11.2 made the lookups inside it cheaper. Neither decided what to ask, and that is the whole of your first week on a repository this size: a ticket in a service nobody on your team has read end to end, and the engineer who wrote the part you need left in March. Lesson 1.4 taught you to ask one question well. This is about the fifty you will ask over the next three days, and the discipline that keeps them from costing more than they return.
Onboarding is the workflow, not a preamble to it
The docs do not treat codebase questions as a warm-up. They treat them as the job:
Using Claude Code this way is an effective onboarding workflow, improving ramp-up time and reducing load on other engineers. No special prompting required: ask questions directly. — Best practices
Reducing load on other engineers is the measure — the alternative to asking Claude is not reading the code yourself, it is interrupting the one person who remembers. And no special prompting required means the failures below are not prompting failures. They are aiming failures.
Broad, then narrow, and the two rungs everyone skips
The documented ladder is broad first, then specific (Common workflows) — Lesson 1.4 walked it. What that page lists alongside it is the part nobody runs:
- Start with broad questions, then narrow down to specific areas
- Ask about coding conventions and patterns used in the project
- Request a glossary of project-specific terms — Common workflows
Read the third bullet against the next recipe down that page, for finding
relevant code: use domain language from the project. You cannot search in
vocabulary you do not have. Where a "shipment" is a Consignment in one package
and a Leg in another, every question in your own words is aimed slightly wrong
and costs a search that returns nothing. The glossary is the cheapest question on
the list and it makes the next forty cheaper:
list the project-specific terms used in packages/fulfilment and what each one means in this codebaseNote the bound to one package — the same decision Lesson 11.1 made with your starting directory. In a monorepo, "broad" means one subtree, not the repository.
Point the question at the source that holds the answer
The docs put this in a table of prompt rewrites, under Point to sources:
| Instead of | Ask |
|---|---|
| "why does ExecutionFactory have such a weird api?" | "look through ExecutionFactory's git history and summarize how its api came to be" |
Same question; the second names where the answer lives (Best practices). The first is not unanswerable — that is the problem. Nothing in it points at the history, so nothing sends Claude there, and the code it can reach holds what the API is, not why it stopped being something else.
Four sources, and they answer different questions:
| What you want to know | Where it lives | How to aim the question |
|---|---|---|
| What this does now, and what it handles | The code | Name the symbol, file or line |
| Why it is like this, what it replaced | The git history | Say "look through the git history of X" |
| What changed here recently, and on top of what | Your git state | Ask directly; no path needed |
| What the tool itself can do | Claude Code's own documentation | Ask about the feature by name |
Rows two and three both land on git, and the docs separate them: Claude Code
gains access to "Your git state. Current branch, uncommitted changes, and
recent commit history" and, as its own bullet, to your terminal and "any command
you could run"
(How Claude Code works).
Access is not a preload — no page says your branch and diff sit in the window
before you ask — and anything deeper than recent is a git log Claude has to
run, which is what the rewrite above asks for in so many words.
The habit generalises past git: if the answer lives in an ADR, a runbook or a schema, say the filename. In practice the answers that come back fluent and wrong are the ones whose real source was never in the window — a reconstruction from the code reads exactly like a recollection of the history.
The infinite exploration, and what a bound actually is
You met the failure in Lesson 1.4, which builds it in full: an "investigate" nobody scoped, and Claude reading hundreds of files into your window. The documented fix is to "scope investigations narrowly or use subagents so the exploration doesn't consume your main context" (Best practices). At this scale "narrowly" cannot mean a smaller question — some questions are genuinely large. It means saying where the answer stops, and three documented prompts show what that looks like:
| Bound | Documented example | Stops when |
|---|---|---|
| A path through the system | "trace the login process from front-end to database" | It reaches the database |
| A likely location | "check the auth flow in src/auth/, especially token refresh" | That subtree is accounted for |
| Somewhere that is not your window | "use a subagent to investigate how our auth system handles token refresh" | Findings come back; the reads do not |
The middle row is the Describe the symptom rewrite from Level 2, whose documented shape is "the symptom, the likely location, and what 'fixed' looks like" (Best practices). Lesson 2.4 sold you the first part: report what you observed, not what you concluded. At this scale the second part is what stops the exploration. The likely location is the bound, and a guess you only half believe beats none — a wrong guess is corrected in one turn; a missing one is replaced by a tree walk.
The third row is Level 8's machinery pointed at a Level 11 problem: exploring a large codebase fills your context with file reads, so the exploration happens elsewhere and only the summary returns (Common workflows).
The @ reference, read at monorepo scale
Lesson 2.2 established the two behaviours: a directory reference gives Claude
the file listing rather than the contents, and a file reference also pulls in the
CLAUDE.md from that file's directory and its parents
(Common workflows). Both
facts change character in a large tree.
The listing was a feature at Level 2 — here is what exists, pick what you need.
In a monorepo, @packages/ can return a listing large enough to be its own
context cost and still contain no code. The CLAUDE.md pull was convenient
there too: the conventions that apply to a file arrive with the file. But Lesson
11.1 had you layering a CLAUDE.md per package precisely so that starting in one
would not load the other eight, and a single @ into a deeply nested file
reaches past that decision. The instructions that load are chosen by where the
file sits, not by where you started.
Questions Claude can answer about itself
The fourth source is the tool itself, and it costs no repository read:
Claude has built-in access to its documentation and can answer questions about its own features and limitations. — Common workflows
Documented examples include "how does Claude Code handle permissions?" and
"what are the limitations of Claude Code?". It is the fastest route to the
questions this course keeps raising mid-task — does a Read deny rule cover a
grep -r run through Bash — without opening a browser tab and losing the thread.
One caveat, and it belongs to you rather than to the tool. "Claude always has
access to the latest Claude Code documentation, regardless of the version you're
using" (Common workflows) is
stated as a benefit, and it is one. It also means the answer describes the
documented feature, which may be newer than the binary on your machine. When an
answer about Claude Code decides something, pair it with the claude --version
habit from Lesson 1.2 — the reason every page in this course names the build it
was verified against.
A question about the tool has nothing to do with the repository you are
onboarding into, and Lesson 3.2's /btw looks like the obvious place to put it:
the answer "never enters conversation history, so you can check a detail without
growing context"
(Best practices). Read its
scope before you build a habit on it.
Checkpoint
-
A teammate asks "why does the billing service retry exactly three times?" and gets a confident, plausible paragraph. They cannot find any of it in the code when they look. What went wrong at the moment they typed the question, and what is the one-line rewrite?
Show answerAnswer
Nothing in the question pointed at a source. It is a why question, so the answer lives in the git history — what the code replaced and why — and no word in it sends Claude there. The code it could reach holds what the retry logic is, not why it stopped being something else, so it reconstructed a reason from the code. That is the failure mode to name: a reconstruction from the code reads exactly like a recollection of the history, which is why the paragraph was both fluent and unfindable. It is an aiming failure, not a prompting one.
The rewrite follows the documented Point to sources pattern — same question, but it names where the answer lives:
look through the git history of the billing service's retry logic and summarize how the retry count came to be. If a comment beside the code would also satisfy them, say which they will accept: answer from the code, and if the code does not say, check the commit that introduced it. -
You type
@packages/payments/and ask whether it handles partial refunds. Name what entered the window and what did not — then say what changes if you reference@packages/payments/refunds.tsinstead.Show answerAnswer
What entered was the file listing for that directory. What did not enter is any source code — and, less obviously, any
CLAUDE.md: the docs attach the memory pull to file references, so the directory form hands you neither the code nor the conventions. In a monorepo the listing can be large enough to be its own context cost while still containing nothing that answers the question, so the answer comes either from a further round of reading you did not ask for or from the filenames.Reference the file and you get its contents plus the
CLAUDE.mdfrom that file's directory and its parents. The second half is not free at this scale: Lesson 11.1 had you layering aCLAUDE.mdper package precisely so that starting in one would not load the other eight, and a single@into a deeply nested file reaches past that decision — the instructions that load are chosen by where the file sits, not by where you started. -
You need to know whether a
Readdeny rule stops a recursivegreprun through Bash. Say why/btwis the wrong lever for it, where you would ask instead, and what the answer you get describes that your installed version might not.Show answerAnswer
/btwis narrower than "a question I want kept out of history". A side question is answered only from what is already in context — Claude can't read files, run commands or search when answering one — and the page's own rule is to use/btwfor what Claude already knows from this session and a subagent to go find out something new. No page says whether the built-in documentation counts as already in context, so this is not a lever to build a docs habit on.Ask in the session and pay the tokens. Claude has built-in access to its own documentation and can answer questions about its features and limitations — the fourth source, costing no repository read, and the fastest route to exactly this kind of mid-task question without opening a browser tab and losing the thread. If you want it off your main thread, press
fon a side question to fork it into a subagent that does have tools, local sessions only.What you get back describes the documented feature. Claude always has access to the latest Claude Code documentation regardless of the version you are running, so the deny-rule behaviour it describes may be newer than the binary on your machine. When an answer about Claude Code decides something, pair it with
claude --version.