Answer code questions structurally instead of reading whole files...
Read is the single largest consumer of context in agent sessions. Measured on
real transcripts: tool results dominate conversation text, Read dominates the
tool-result tokens, and a single Read call averages 1,563 tokens.
Most Read calls answer a question that did not need the whole file.
| tool | tokens per call |
|---|---|
Read |
1,563 |
get_outline |
113 |
find_symbol |
102 |
search |
79 |
find_word |
41 |
read_symbol |
35 |
The codeindex tools are named bare throughout this skill. Their live prefix
depends on the install: mcp__codeindex__ when the server is registered
directly, mcp__plugin_codeindex_codeindex__ when the plugin registers it. Take
the exact name from your own tool list β a name written for the other install
fails the call and sends you back to Read.
Some harnesses defer MCP schemas: the names are in your tool list, but calling
one before its schema loads fails validation. Load the schemas first, in one
call β ToolSearch with select:find_symbol,read_symbol,get_outline,find_word
β then call the tools. That is one extra call per session, against 1,563 tokens
for every file you would otherwise read.
A token you never put into context is never billed. A token you put in and later compress has already been re-sent on every intervening turn, and editing it invalidates the prompt cache. So the cheapest possible intervention is to not read the file in the first place.
Ask what the question actually is, then pick:
find_symbol (name). Returns file and line, not a
file. Do not Grep for a definition.read_symbol (name, optional path to
disambiguate, context for extra lines). This is the big win: 35 tokens
against 1,563 for the file that contains it.get_outline (path). Symbols with line numbers.
Read the outline first, then read_symbol the one you want.find_word for an exact
identifier, search for free text. Both beat Grep on token cost.find_callers (name). Each hit names the calling
function. It matches by name, so a different definition with the same name
shows up too β treat the result as a candidate list, not proof.get_change_impact (path,
optional max_depth) for the transitive blast radius, or plan_change for
the whole picture in one call (definition, call sites, file role, literals,
blast radius).Dependency questions: get_imports (path) for what a file needs, and
get_imported_by (path) for what needs it. Orientation: get_tree,
get_hot_files, status. Audits: analyze with one of 22 analyses
(security, dead_code, cycles, architecture, unwrap_audit, clones,
duplication, health, β¦).
Production-cost questions have their own analyses. Ask spawn_scan what starts
an interpreter on a timer, field_contention which declared-state field two
owners write, logic_shapes which fixed byte constant ignores its unit's
memory limit and which pool opens more connections than the pooler takes, call_cost which loop makes the most round trips per element,
leak_shapes which container only grows, and deps what the dependency tree
holds. A leak_shapes finding is a SHAPE: it names the runtime
series that decides it, so pair it with that series before acting.
Every file-scoped tool above takes path, relative to the workspace root.
It is never file. A wrong argument name costs a turn and then sends you back
to Read, which is the outcome this skill exists to avoid.
Three cases where reaching for codeindex is wrong, and one is a trap:
Edit, the whitespace
matters, or you need lines the outline does not carry. Use Read. Being
cheap is worthless if you then edit the wrong text.read_file is not a cheaper Read. Measured at 1,109
tokens per call against Read's 1,563 β the same job at a similar price. The
saving comes from asking a narrower question, not from swapping the file
reader. Prefer read_symbol.get_outline on a very large file can cost more than Read. Read
truncates long files; an outline enumerates every symbol. On a 4,000-line
file the outline can exceed a truncated read several times over. Use the
outline to orient in a normal file, not as a universal Read replacement.Also skip it for non-code files, generated files, and anything the index has not
seen β check status if results look empty, and index_workspace if the
workspace is not indexed yet.
An empty structural result has two very different causes, and they lead to opposite actions:
status separates them in one cheap call. Two fields decide it:
files β 0 means nothing is indexed at all.workspace β the absolute root actually indexed. In --mcp mode the server's
working directory is chosen by the client, not by you, so this can be a plugin
directory, a config directory, or a different repository altogether. An index
of the wrong tree answers every question just as confidently as the right one.If either is wrong, index_workspace with path set to the absolute path of the
project fixes it for the rest of the session, watcher included. A refused
workspace also says so in every tool result, so a result that starts with
"codeindex has no index" is a configuration problem, never a code answer.
Read. Everything else has a cheaper structural
answer above.find_symbol β read_symbol
costs about 137 tokens where reading the file costs about 1,563.status before concluding the
code is absent β an unindexed or wrongly indexed workspace looks identical to
a missing symbol. See the section above for the two fields that tell them
apart.