Codebase Literacy at Scale: Using AI to Understand Code You've Never Seen
Pasting files into a chat window breaks down past roughly 5,000 lines of code. Here's how to combine AI retrieval with targeted questions to onboard onto unfamiliar code in hours, not days.

Understanding an unfamiliar codebase fast means combining retrieval-based context (letting an AI tool index and search the repo) with targeted questioning that mimics how a senior engineer investigates: start broad, narrow to entry points, then trace data flow. AI shortens this from days to hours, but only when you feed it structure, not just text.
Why "just paste the code into ChatGPT" fails past 5,000 lines
The naive approach, dumping files into a chat window, breaks down for three reasons. First, context windows. Even a 200K-token window (roughly 150,000 words, per Anthropic's documentation) fills up quickly once you include a monorepo's shared utilities, generated types, and test fixtures. Second, relevance decay: models attend less reliably to information buried in the middle of a long context, a phenomenon sometimes called "lost in the middle." Third, and most overlooked, pasted code loses its graph. A function's meaning depends on who calls it and what it calls, and flat text strips that out.
The fix isn't a bigger context window, it's retrieval. Tools like GitHub Copilot's workspace features, Cursor, and Sourcegraph Cody build an index (often embeddings plus symbol graphs from language servers) and pull only the relevant slices into context per query. That's why "explain this repo" prompts work better in an IDE-integrated tool than in a raw chat interface: the tool decides what's relevant, and can re-fetch as your questions change.
What actually works: a five-layer approach
I use a consistent sequence when I inherit a codebase, whether it's a client project or an open-source dependency I need to patch.
1. Get the shape before the substance
Before asking an AI anything about logic, ask about structure:
1Summarize this repository's top-level directory structure. 2For each major directory, state its apparent responsibility 3in one sentence, based on file names and any README content.This is cheap (low token count, fast response) and catches obvious wrong assumptions early. If the tool says services/ contains business logic but you later find it's all dead code from a migration, you've saved yourself from building a mental model on sand.
2. Find entry points and trace one request end to end
Every codebase has entry points: HTTP handlers, CLI commands, message queue consumers, cron jobs. Ask the AI to enumerate them, then pick one and trace it:
1Trace the full execution path for a POST request to /api/orders, 2starting from the router. List every function called, in order, 3with file and line references. Note any async boundaries (queues, 4webhooks, background jobs) where the trace would need to continue 5in a different process.This is where tool choice matters most. A tool with real static analysis (Cursor's codebase indexing, or Copilot's workspace context in VS Code) will actually follow imports and function calls. A chat model working from a partial paste will guess, and guess confidently. I've seen Claude and GPT-4 class models both hallucinate a plausible-sounding call chain when the actual file wasn't in context. Always ask for file and line references, not because they're always right, but because wrong references are your signal to verify manually.
3. Ask "why," not just "what"
The most valuable questions target intent, because that's what's missing from the code itself:
1This function retries three times with exponential backoff capped 2at 30 seconds, but only for 5xx errors, not 4xx. Is there a comment, 3commit message, or related test that explains this specific choice? 4If not, what's the likely reasoning based on the calling context?Tools that can search commit history and linked issues (GitHub Copilot Chat with repo context, or Cody with its enterprise search) give much better answers here than a plain LLM, because git blame and PR descriptions often contain the actual "why" that the code alone can't tell you.
4. Generate a test to confirm your understanding, don't just trust the explanation
AI explanations of code are frequently plausible and occasionally wrong, especially around edge cases and off-by-one conditions. The check I trust more than any explanation is a generated test that I then run:
1Write a unit test for parseInvoiceLineItems() that exercises the 2case where quantity is a decimal (e.g., 2.5 kg). Predict the 3expected output before running it, then I'll confirm.If the AI's stated expectation matches what the test actually returns, your model of the function is probably right. If it doesn't, you've found either a bug or a misunderstanding, both worth knowing.
5. Build a durable artifact, not just a chat log
Chat history is a bad place to store understanding. It's not searchable by teammates, it's not versioned, and it decays out of context windows. After a serious investigation, I have the AI draft a short markdown doc: architecture summary, entry points, known gotchas, and open questions. That goes into the repo (docs/architecture-notes.md or similar) as a real commit. This is the difference between using AI for a one-off answer and using it to build institutional knowledge.
Does semantic search actually beat grep for onboarding?
Sometimes, not always. Semantic search (embedding-based retrieval) wins when your query is conceptual: "where do we handle currency rounding" will find relevant code even if the word "rounding" never appears. Plain grep or ripgrep wins when you know the exact symbol or string and want every occurrence with zero ambiguity, and it's instant, no indexing lag, no API cost.
In practice I use both. Semantic search to find the neighborhood, then rg to get an exhaustive list once I know the function or constant name. Relying only on AI search risks missing occurrences that fell outside the embedding model's similarity threshold, which happens more often than vendors imply. I've had Cody and Copilot both miss a usage that a two-second rg "FEATURE_FLAG_NAME" caught immediately.
Cost and latency realities
Indexing a large monorepo (500K+ lines) for the first time is not instant. Cursor's and Cody's initial indexing can take several minutes to over an hour depending on repo size and your machine or the remote indexing service, and incremental re-indexing on every commit adds background load. If you're evaluating a tool for a large codebase, test indexing time on your actual repo before committing to a workflow, not on the vendor's demo repo.
Query latency also varies. A single "explain this function" call to a hosted model typically returns in a few seconds. But multi-step agentic exploration, where the tool autonomously reads several files, calls a tool, reads more files, and synthesizes an answer, can take thirty seconds to a few minutes and burn through meaningfully more tokens (and API cost, if you're paying per-token rather than a flat subscription). For a large team running these agentic traces routinely, that cost adds up in a way a flat per-seat Copilot subscription doesn't.
When AI-assisted exploration is the wrong tool
There are situations where I skip AI entirely and go straight to manual reading or classic tooling:
Security-critical review. If you're auditing authentication or payment code for a vulnerability, an AI's confident but occasionally wrong summary is dangerous precisely because it sounds authoritative. Manual review, with AI as a second opinion rather than the primary source, is the safer order of operations.
Extremely small, well-organized codebases. A 2,000-line service with a clear README and consistent naming doesn't need semantic search or agentic tracing. Reading it directly is faster than setting up a tool, and you build a better mental model by doing it yourself.
Codebases with heavy generated or vendored code. If half your repo is node_modules-style vendored dependencies or generated protobuf code, AI tools often waste indexing time and context budget on files you'll never need to understand. Configure .gitignore-style exclusion patterns (most tools, including Cursor and Cody, support an ignore file) before you start, or you'll get diluted, less relevant answers.
When you need legal or compliance certainty about license provenance. AI can describe what code does; it's a poor source for confirming licensing history or third-party attribution. Use dedicated SCA tooling for that.
A workflow for the first day on a new codebase
Here's the sequence I actually run, in order, on day one of a new project:
- Ask for directory structure and responsibilities (five minutes, low cost).
- Identify entry points and pick the two or three most business-critical ones.
- Trace one request end to end, demanding file and line references.
- Cross-check one non-trivial function by generating and running a test.
- Search git history for the "why" behind anything that looks like a deliberate, non-obvious design choice.
- Write up findings as a committed markdown doc, not a saved chat.
- Only after steps 1 through 6, start making changes.
The teams that get real value from AI-assisted codebase literacy treat it as a faster way to do the same investigative work a careful engineer already does, not a replacement for that investigation. The moment you skip the verification step (running the generated test, checking the line reference, reading the actual diff) is the moment AI-assisted understanding becomes AI-assisted overconfidence, and that failure mode is more expensive than the hours you saved getting there.
Related Articles

How to build a multi-file feature using Cursor Composer
Get the scoping wrong in Composer and it will happily rewrite files you never meant to touch at all. Here's the exact workflow for scaffolding and modifying multi-file features safely.

Cursor vs the Field: When AI-Native IDEs Beat Traditional Editors with AI Plugins
The fork-vs-plugin debate online misses the real difference: context management. Here's what separates Cursor's own indexing pipeline from a plugin-based assistant like Copilot.

How to configure .cursorignore to prevent context pollution and protect secrets
Cursor indexes your working directory, not just what Git tracks, so an untracked .env file can still leak straight into a prompt. Here's how to lock that down properly.