Skip to content
ivralo
Sections

Docs / Developer mode

Code intelligence

ivralo reads code through the language servers your project declares, a code index that caches what they and git say, and a set of read tools that answer without filling a small context window. This page covers declaring a server, the tools, the index, editing by symbol, and the exploration budget.

Declaring a language server

A language server knows which login a call reaches, every real use of it, its type and what the checker says about a file. ivralo ships no list of servers and starts nothing on its own: it asks the servers your project declares in IVRALO.md, one line per set of file suffixes.

# Language servers

- py: pyright-langserver --stdio
- ts=typescript,tsx=typescriptreact,js=javascript: typescript-language-server --stdio

Suffixes come with or without their dot. suffix=id names the language identifier the server is told a file is; without it the suffix itself is sent. A longer suffix (d.ts) wins over a shorter one, and a suffix on two lines stays with the first. Name the server by a program on your PATH or a path inside the repository.

Trust is the approval. Starting a server runs a program, and a cloned repository brings its own IVRALO.md, so nothing it declares starts until you trust the folder. Once you have, the first question about a .py file starts the py line's server with no second question, in the session, in ivralo ask, in a schedule and in ivralo index --code alike. The shell policy still judges the command first, and a deny entry refuses it. Read the # Language servers lines before you trust a folder: they will run.

The server runs in ivralo's own process tree, in the repository, with the shell's environment, and ends when ivralo does. A crashed server is restarted once; after a second crash the tools say so for the rest of the session.

SettingDefaultEffect
IVRALO_LSP_TIMEOUT30Seconds one request to a server may take
IVRALO_LSP_WARMUP_WAIT15Seconds to wait for a server that is still indexing

ivralo doctor has a language servers section: each line, whether its command is on PATH, what your policy says about starting it, and for a server it may start, its version, what it can answer and how long it took to warm up.

The language-server tools

ToolAnswers
goto_definitionWhere the symbol at a position is defined
find_referencesEvery use of it, counted first; within= narrows, limit (at most 200) lengthens
find_implementationsThe classes or functions that implement an interface or abstract method
call_hierarchyWho calls a function, or what it calls, one level
hover_infoThe symbol's type or signature, then its documentation
code_diagnosticsThe errors and warnings the server reports for a file, errors first
rename_symbolA rename at every site the server finds; an edit, shown before it lands
organize_importsThe server's own organize-imports action; an edit

A position is a line and the name on it (symbol="login"), or a 1-based column. What a server cannot answer is said, never returned as an empty list: a suffix no line covers, a question the server does not support, a server still warming up.

The code index

The code index is a cache in .ivralo/index/index.sqlite of what your language server and git say about the repository. It parses nothing itself. It stores declarations (classes, functions, methods, module-level names, class fields), not the variables inside a function.

ToolAnswers
symbol_searchWhere a name is defined: exact names first, then prefixes, then names holding it; source before tests
file_outlineOne file's symbols with their line ranges, so the agent reads only the lines it needs

Every answer opens with how much of the repository is indexed and at which commit, and a hit whose file changed since is marked stale. Each turn refreshes the index for at most IVRALO_CODE_INDEX_BUDGET seconds (2 by default; 0 turns it off), so a large repository fills over several turns and never holds one up. To pay the whole cost at once:

ivralo index --code             # read every file now
ivralo index --code --rebuild   # start over
ivralo index --code --semantic  # also embed code for semantic_code_search

It is a cache: deleting .ivralo/index/ costs a rebuild and nothing else. ivralo doctor says which commit it reflects and how far behind HEAD that is.

The read surface

A third set of tools lets an agent read a repository without reading whole files into its context. Each is a query over the index, the language server, git or the knowledge index; none is a parser. Each answer puts its count first and says when its source is stale or missing.

ToolAnswers
repo_summaryWhat IVRALO.md declares, files by suffix, the top-level layout, the files that change most, the README's first paragraph
repo_treeDirectories first with their file counts, a few levels deep
related_filesFiles that change in the same commits, use the file's symbols, or share its name, each with why
related_testsThe tests that reference a symbol, then the file's related tests
inheritance_graphA type's supertypes and subtypes
dead_code_candidatesSymbols nothing in the workspace references; candidates only, nothing deleted
code_sliceOne symbol as a package: its code, its class line, the imports it uses, the signatures of what it calls, its test, within IVRALO_SLICE_BUDGET tokens (2,000); the header lists what was left out
semantic_code_searchCode by what it does ("where is the token validated"), cited by file, lines and symbol

semantic_code_search embeds code a little at each call, or all of it with ivralo index --code --semantic. With a hosted embedding model it refuses, so code does not leave the machine, unless IVRALO_EMBED_CODE_HOSTED=1.

Editing by symbol

Where a language server is configured, the agents can change code by naming what they change instead of copying it into edit_file:

ToolDoes
replace_symbol(path, symbol, new_text, line=0)Replace one function, method, class or constant
insert_before_symbol, insert_after_symbolAdd lines just before or after a symbol
delete_symbol(path, symbol, line=0)Delete a symbol, only when nothing else refers to it
add_import(path, statement)Add an import at the end of the import block, once
replace_range(path, start_line, end_line, new_text, expected_text)Replace lines that are exactly the text expected, for a file no server covers
format_file(path), format_changed_files()Run your project's own formatter

A symbol is named as file_outline shows it (login, or Session.login), and line settles an ambiguous name. Every edit needs the file read first; if the symbol's lines changed since, it stops with PATCH_CONFLICT. Every other byte of the file stays as it was.

After an edit lands, the server's errors for the file are compared with those before it, and a new one is reported. IVRALO_EDIT_REFUSES_ON_DIAGNOSTIC=1 rolls the edit back instead.

ivralo never formats with a tool of its own. Declare yours:

# Commands

- format-paths: `uv run ruff format {paths}`

format-paths gets the files in its {paths} slot. With only format declared, the formatter runs over the whole workspace; with neither, nothing is formatted.

write_file on a file that exists is refused for the coder, with the symbol edits named instead; IVRALO_WHOLE_FILE_WRITES=1 allows it. All symbol edits ask like any edit, and edit_file in allow_tools covers them unattended (Editing and approvals).

The exploration budget

Every read tool has an exploration level, from cheap to expensive, and the coding skill reads in that order:

LevelTools
1repo_summary, repo_tree, glob_files
2symbol_search, file_outline, grep_files, related_files, related_tests
3code_slice, goto_definition, find_references, find_implementations, call_hierarchy, inheritance_graph, hover_info, semantic_code_search
4read_workspace_file

What a turn spent exploring is counted and shown beside the context figure, explored 3.1k tokens (level 2), and in the turn summary and ivralo ask --format json. By default it is advice only. Set a budget and it is enforced:

IVRALO_EXPLORATION_BUDGET=20000     # tokens per specialist per turn; 0 = advice only
IVRALO_EXPLORATION_FILE_LINES=200   # the widest read never refused

With a budget on, a read of more than 200 lines is refused until the agent has an outline of that file this turn, and past the budget a level-3 call or such a wide read is refused too. Each refusal names the cheaper call. The budget yields wherever the cheap levels cannot answer: no language server declared, no symbols for the file, a file git does not list.

Whatever the budget, the same read asked twice in one run, with nothing written in between, is answered "you already have this" instead of running again.