In this guide
Gemini CLI is often introduced through its large context window, and the obvious conclusion is that you can skip the hard part: put the whole repository in the prompt and let the model sort it out. Sometimes that works. Often it works less well than expected, costs more than it should, and leaves you unable to tell which part of the code the answer was actually based on.
The real question on a large repository is not "how much can the model hold" but "what should it be looking at for this task". This guide covers how Gemini CLI gets context (GEMINI.md files, file references, and MCP servers), when stuffing a lot of code into the window is the right call, when targeted retrieval wins, and a workflow that combines them.
Key takeaways
- Gemini CLI loads GEMINI.md files hierarchically. Use them for durable, curated facts about build commands, layout, and rules, not for dumping code.
- Long context is excellent for reading a bounded area deeply. It is a poor substitute for knowing which area to read.
- Retrieval, especially structural retrieval over a code graph, answers "where" and "who calls" questions precisely and cheaply.
- MCP servers are configured in Gemini CLI's
settings.json. A code graph server gives the agent definitions, callers, and dependents on demand. - The strongest workflow is retrieval first to find the right files, then long context to read them together.
How Gemini CLI assembles context
There are three main channels.
GEMINI.md files. Gemini CLI looks for context files named GEMINI.md and combines them hierarchically: a global file in your user configuration directory, a file at the project root, and files in subdirectories. The combined content is sent with your prompts. The CLI includes a /memory command for inspecting and refreshing what has been loaded, which is worth using when you are unsure whether an edit to the file has taken effect.
Explicit file references. You can point the CLI at specific files or directories in your prompt so their contents are included. This is the direct way to use the long context window: choose the files and hand them over.
Tools. The agent can run built-in tools (reading files, searching, running shell commands) and any tools exposed by MCP servers you have configured. This is where retrieval happens.
Understanding which channel a piece of context arrives through matters, because each has a different cost profile. GEMINI.md content is paid for on every turn. Referenced files are paid for once per inclusion. Tool results are paid for only when the agent asks.
GEMINI.md: curated facts only
Treat GEMINI.md as the onboarding note you would give a contractor on day one. A useful root file is short:
# GEMINI.md
## What this repo is
A Python API (FastAPI) in `api/`, a React admin app in `admin/`, and shared
schemas in `schemas/`. Background jobs run with Celery from `api/worker/`.
## Commands
- Install: `uv sync`
- API tests: `uv run pytest api/tests -q`
- Single test file: `uv run pytest api/tests/test_orders.py -q`
- Admin typecheck: `npm --prefix admin run typecheck`
## Rules
- Pydantic models in `schemas/` are the source of truth for request and response shapes.
- Never call the payments provider directly; use `api/payments/gateway.py`.
- Migrations are generated with Alembic (`uv run alembic revision --autogenerate`); do not hand-write them.
Subdirectory files carry local rules. A GEMINI.md in api/payments/ might say that every new gateway method needs an idempotency key and a test using the recorded fixtures. Keep each file focused on its area.
The anti-pattern is pasting large chunks of code or documentation into GEMINI.md because "the model has room". It does, but you will pay for that content on every turn, and the rules you actually care about get buried. For a full treatment of instruction files across agents, see writing AGENTS.md and CLAUDE.md; the same principles apply to GEMINI.md.
Long context: what it is good at
A large window changes what is practical once you know which files matter. It is the right tool when:
- You need to read a bounded subsystem as a whole. Understanding how the order lifecycle works across a model, three services, and a state machine is easier when all of them are in view at once.
- The task is cross-cutting within a known area. Renaming a concept across 20 files in one package, or making error handling consistent in one service.
- You are reviewing. Feeding a diff plus the files it touches lets the model reason about the change with its surroundings.
- You are explaining. Summaries and walkthroughs of a known area benefit from seeing everything together.
In all of these, a human or a prior step has already decided the boundary. Long context then removes the need to page code in and out.
Long context: where it falls short
Putting most of a large repository into the prompt has real costs.
Attention is not uniform. Models are generally better at using information that is relevant and well positioned than at finding one critical line among a very large amount of loosely related text. More context means more distractors.
Cost and latency scale with input. Every turn that re-sends a huge context pays for it again. Iterative work multiplies this.
Provenance gets fuzzy. When the answer is based on "the whole repo", it is harder to check which file a claim came from. Grounded answers with file and line references are easier to verify.
It still does not show relationships directly. Reading 2,000 files does not produce a call graph. The model has to infer that submit_order is called by the retry worker through a task registry, and inference across that much text is exactly where mistakes creep in.
The deeper comparison of retrieval styles is in code knowledge graph vs embeddings.
Retrieval: answering "where" and "who"
Retrieval flips the approach: the agent asks for what it needs, when it needs it. On code, the most useful retrieval is structural:
| Question | Text search answer | Structural answer |
|---|---|---|
Where is submit_order defined? | every line containing the string | the definition, with path and line |
| Who calls it? | lines containing submit_order( | direct and indirect callers, including through the registry if modeled |
What breaks if schemas/order.py changes? | not answerable | the list of importing modules and their tests |
| Where should I start for "orders stuck in pending"? | keyword hits | files ranked by relevance to the task |
Configuring an MCP server
Gemini CLI reads MCP server definitions from its settings.json, either the user-level file or a project-level one inside a .gemini folder in the repo. Servers are listed under an mcpServers object, each with the command that launches it and its arguments:
{
"mcpServers": {
"code-graph": {
"command": "<command that starts the server>",
"args": ["<arg>", "<arg>"],
"env": {}
}
}
}
Use the project-level file when the whole team should share the server, and keep credentials in environment variables rather than committed JSON. After restarting the CLI, the server's tools are available to the agent. Add a line to GEMINI.md telling it to prefer these tools for definitions, callers, and dependents, and to use plain search for config keys and string literals.
The combined workflow
Retrieval and long context are not competitors. The pattern that works best on large repos uses each for what it does well.
Step 1: retrieve to find the boundary
Investigate only. For the bug "orders stuck in pending after payment succeeds",
find the code that transitions an order out of pending, every caller of it,
and the webhook handler for payment success. Give file:line anchors.
With a code graph server, this is a few targeted calls. The output is a short list: perhaps eight files and a dozen symbols.
Step 2: load the boundary into context
Now reference those eight files explicitly and ask the model to read them together:
Read these files together and explain the full path from the payment webhook
to the order status change, including any async steps.
This is where the large window earns its keep. The model sees the webhook, the queue, the worker, and the state machine in one view.
Step 3: plan and implement with checks
Ask for a plan that names files, approve it, then implement with tests after each step. Run the specific test file, not the whole suite, until the end.
Step 4: verify against dependents
Before finishing, ask the agent to list dependents of every file it changed and confirm each is unaffected or updated. This catches the caller nobody thought about.
The sequence costs less than loading the repository up front, and every claim in the final answer traces back to a file the agent was deliberately shown.
Practical tips
- Exclude noise. Make sure generated code, build output, and vendored dependencies are ignored, both by your VCS ignore files and by any ignore mechanism the CLI supports. They waste context and mislead the model.
- Start in the right directory. Launching from the relevant package narrows default exploration and picks up that area's GEMINI.md.
- Ask for anchors. Request
path:linereferences for every claim. It makes answers checkable and discourages invention. - Reset between tasks. A long session drags its earlier context along. When switching topics, start fresh; your GEMINI.md and MCP tools make that cheap.
- Watch for confident summaries of unread code. If the agent describes a file it never opened or retrieved, ask it to fetch the file and check.
When to reach for which
| Situation | Prefer |
|---|---|
| You do not know where the relevant code is | retrieval |
| You know the area and need deep understanding | long context over that area |
| You need callers, dependents, or blast radius | structural retrieval |
| You are reviewing a diff | diff plus touched files in context |
| You need a repo-wide overview | a generated skeleton or map, not the full source |
Where OpenVisio fits
OpenVisio indexes a repository locally and exposes the code graph over MCP, so Gemini CLI can call tools such as resolve_context to find the boundary for a task, trace_calls for callers, and get_dependents for blast radius, then read only the files that matter. For humans doing the same orientation, the Tour walks through the codebase stop by stop so you know what to point the agent at.
A big context window is a genuine advantage. It is most valuable when something else has already decided what belongs in it.

