π«π· Version franΓ§aise
See also: RaggableTree guide Β· Back to index
ADR β RaggableTree semantic graph as the agents' context substrate
Status: Accepted Β· Date: 2026-04 Β· Scope: Orkeon.Analysis + Orkeon.Tools.Analysis
Context
Orkeon agents reason over real codebases that frequently exceed hundreds of thousands of lines across several languages (TypeScript, C#, Python, Go, Rust). Three hard constraints:
- Token budget β The LLM context (even 1M tokens) cannot absorb a monorepo; a compact index is needed that answers "which symbol is affected by X?" without reloading the sources.
- Variable granularity β Depending on the task, an agent may need a package view, a method snippet, a call chain, or a complexity measurement. A single representation (raw AST, flat embeddings, Markdown documents) does not cover all these cases.
- Iteration cost β A project evolves continuously; rebuilding the full index on every commit is unacceptable (measured: 20Γ slower than a targeted incremental reindex).
The available naive solutions (file reading via file_read, full-text grep, RAG search over arbitrary chunks) were evaluated and deemed insufficient: they do not preserve semantic relations (imports, calls, inheritance) and force the agent to rediscover the structure on every query.
Decision
Build a stratified semantic graph β five NodeLevels plus the edge layer β fed by Tree-sitter, exposed to agents through 13 structural tools.
The five levels (NodeLevel) and the edges:
- L0 Monorepo β root of the indexed project
- L1 Package β build unit detected by marker (
package.json,*.csproj, ...) - L2 Module β source file
- L3 Symbol β class, interface, function, method, enum, property, constant
- L4 Statement β if/try/loop/return extracted for flow and CFG queries
- Edges β Imports, Calls, Extends, Implements, Contains
Seven key components implement the pipeline:
ILanguageAdapterβ per-language adaptation (Tree-sitter queries + import heuristics)RaggableTreeBuilderβ initial build (6 phases)IncrementalReindexEngineβ diff reindexing (changed files only)IRaggableStoreβ queries over the built graphIEmbeddingProvider+IEmbeddingTextComposerβ semantic searchIFrameworkFingerprinterβ tagging nodes by framework (Angular, NestJS, ASP.NET, Flask, FastAPI)ICodebaseWatcher+IRaggableTreeEventBusβ real-time synchronization
Rejected alternatives
Full LSP (Language Server Protocol)
Integrating one LSP server per language (tsserver, OmniSharp, pylsp, ...) provides very precise information about symbols and references.
- Rejected because: it requires one runtime per language (Node.js for tsserver, MSBuild for OmniSharp, a Python venv for pylsp) and long-running process orchestration. Impractical for a batch indexing pipeline on CI or on a server without the SDKs installed.
Roslyn-only (C# only)
Roslyn provides a perfect AST and a resolved symbol graph for C#.
- Rejected because: porting Python/JavaScript/Go/Rust would be a major functional loss. The target is a multi-language framework by default.
Full-text search + flat embeddings
Split each file into 500-token chunks, vectorize them, store them in a vector store, and let agents do semantic search only.
- Rejected because: it loses the structural relations (who calls what, who inherits from what, which imports). The
flow_trace,impact_analysis,sub_graphtools become impossible. Answer quality drops on questions of the form "if I change X, what breaks?".
Regex/ctags over AST
The fastest option to implement but the most fragile: it does not distinguish real calls from mentions in comments, does not resolve imports, and misses modern constructs (async/await, decorators, spread).
- Rejected because: technical debt grows with every new language or framework. Tree-sitter offers an officially maintained grammar for 40+ languages.
Consequences
Positive
- Compact context β
ICodebaseContextProviderproduces a summary < 500 tokens (markdown) or < 200 tokens (compact) that can be injected into all agents. - Typed queries β The 13 tools replace dozens of lines of "read this file and tell me..." prompting with deterministic calls.
- Incremental reindexing β The engine re-parses only the changed files (measured target: < 5% of the initial cost).
- Multi-language by construction β Adding a language = implementing an
ILanguageAdapter, not extending a C#-only pipeline.
Negative
- Large API surface β 7 interfaces + 5 adapters + 13 tools = 25 extension points to understand before extending the system. Mitigated by the
docs/architecture/raggable-tree.mddocs and the present ADR. - Tree-sitter as a native dependency β The parsers are compiled in C; musl or ARM32 builds may require work. Mitigated by
TreeSitter.DotNet, which wraps the compilation for most target platforms. - Memory cost β A 100k-symbol monorepo with 1536-dim embeddings weighs ~600 MB in memory. Mitigated by the option of using an external vector store (Redis/LanceDB) rather than
InMemoryRaggableStore. - Embedding provider optional but strategic β Without embeddings,
codebase_searchandsemantic_searchare disabled. The pipeline remains useful for the structural tools (map, detail, graph, flow) but loses its semantic component.
Accepted risks
- TypeScript re-exports (
export { Foo } from './bar') and dynamic Python imports can produceUnresolvedRef. Decision: document the limitation rather than build a heavy resolver in V1. - The JSON cache is unversioned and therefore invalid across adapter changes. Decision: recompute on demand, with no automatic migration.
Amendment β 2026-08-18
The tool surface has since grown from the 13 tools this record describes to
15 (Orkeon.Tools.Analysis); the derived "25 extension points" figure is
now 27. The counts above are kept as written β this ADR is a frozen decision
record; the RaggableTree guide is the authoritative,
maintained inventory.
See also: RaggableTree guide Β· Back to index