cd /news/developer-tools/trelix-v1-0-to-v2-7-when-it-works-me… Β· home β€Ί topics β€Ί developer-tools β€Ί article
[ARTICLE Β· art-53201] src=dev.to β†— pub= topic=developer-tools verified=true sentiment=↑ positive

trelix v1.0 to v2.7: When "It Works" Meets "It Scales"

Trelix evolved from v1.0 to v2.7 in thirteen days, fixing a critical config bug and adding a knowledge graph, seven retrieval legs, agentic loops, federated multi-repo search, and a GitHub Actions bot. The knowledge graph module builds a CodeGraph with Louvain community detection and LLM-based concept extraction, while new retrieval legs are grounded in papers like RAPTOR, HyDE, and FLARE. A deliberate breaking change renamed `trelix graph` to `trelix call-graph` to reserve the name for the knowledge graph feature.

read9 min views1 publishedJul 9, 2026

Twelve days after I shipped trelix v1.0.0, I was staring at a RetrievalConfig

object with two conflicting sets of values and no idea which one was actually running. I'd built AdaptiveRouter

to accept a retrieval_config

parameter so callers could override the environment-variable defaults programmatically. Except it didn't. The constructor took the parameter, and then quietly ignored it and built its own instance from env vars anyway. Nobody had wired the plumbing from Retriever

through QueryPlanner

down to AdaptiveRouter.__init__

. It's the kind of bug that doesn't throw β€” it just makes your carefully-set config a decoy.

That fix landed in v2.7.0, PR #55, thirteen days and seven minor releases after launch. In between, trelix went from "search my repo well" to something closer to a platform: a knowledge graph, seven fused retrieval legs, an agentic loop, federated multi-repo search, and a GitHub Actions bot that reviews your PRs. Here's what actually shipped, grouped by what it was trying to solve rather than by version number.

v1.0 already had hybrid BM25 + vector + call-graph search. What it didn't have was any notion of the codebase as a system β€” which files cluster into modules, which symbols sit at the center of the import graph, which concepts a human would use to describe an architecture. v2.0.0 (2026-06-28) and v2.1.0 (2026-06-30) fixed that.

The new trelix/graph/

module builds a CodeGraph as a NetworkX MultiDiGraph

, unifying call, import, and type edges into one traversable structure. On top of that, Louvain community detection clusters the graph into architectural modules β€” run trelix graph ./repo

and you get the top communities, not just a flat symbol list. ConceptExtractor

layers an LLM on top of symbol batches to name those communities in plain English, and it's built to fail quietly: any extraction error returns []

rather than crashing the pipeline. GraphVisualizer.export_html()

renders the whole thing as an interactive Pyvis HTML page with community coloring, gated behind pip install trelix[knowledge-graph]

so the base install doesn't inherit the dependency weight.

Graph search became a first-class retrieval leg β€” graph_search_enabled=True

runs a CodeGraph BFS as a fourth leg after RRF fusion β€” and pagerank_boost_enabled

uses import-graph centrality to boost symbols that sit at architectural chokepoints. None of this is static: GraphUpdater.update_file()

is wired into trelix watch

, so the graph and its communities update incrementally as files change, instead of requiring a full rebuild.

This came with the release's one deliberate breaking change: trelix graph

β€” which used to mean "show me callers and callees of this symbol" β€” got renamed to trelix call-graph

. The name trelix graph

now means "build the knowledge graph." I made the call that a growing surface area needed the more intuitive name reserved for the bigger feature, and documented the rename explicitly in the changelog rather than let people discover it by trial and error.

v1.0 had three retrieval legs. By v2.2.0 it had seven, and every one of them is grounded in a specific paper rather than a hunch.

The fourth leg was the graph BFS above. The fifth is RAPTOR-style (arXiv:2401.18059) file-level summarization β€” file_summary_leg_enabled

, gated behind TRELIX_FILE_SUMMARIES_ENABLED=true

at index time β€” which lets trelix answer "explain this codebase" questions that no symbol-level chunk could answer alone. The sixth is HyDE (arXiv:2212.10496): instead of embedding your raw natural-language query, hyde_fallback_enabled

generates a synthetic code snippet and embeds that, closing the semantic gap between "how do I validate a JWT" and the actual token-validation code. The seventh is multi-query expansion, which decomposes one query into N variants and RRF-fuses the independent retrievals for broader recall.

Layered over all seven is FLARE (arXiv:2305.06983) β€” a confidence-gated re-retrieval loop that watches synthesis output for uncertainty phrases and triggers another retrieval pass when it finds them, rather than committing to a possibly-wrong first answer.

None of this is worth shipping without a way to measure whether it's actually better, so v2.1.0 added a CoIR-format eval harness (ACL 2025, arXiv:2407.02883) β€” trelix eval --golden <file>

reports nDCG@10, Recall@10, and MRR, implemented as pure-Python trelix.eval.ndcg

with zero pandas dependency. Every query now also writes a row to a query_telemetry

SQLite table β€” latency, intent classification, result count β€” surfaced through trelix telemetry

.

Here's the detail that actually matters: in v2.1.0, MultiQueryExpander

existed as a class but nothing called it. It took until v2.3.0 (2026-07-02) for it to get wired into _retrieve_standard

, and even then I had to be careful about one specific line β€” variants[1:]

is used, not variants[:] , so the original query never runs twice through the fusion. It's a one-character difference between "seven legs" and "seven legs, one of them redundant."

v2.2.0 (2026-07-01) shipped across four parallel feature branches β€” PRs #29 through #32, merged via release PR #33 β€” and it's the release where trelix stopped being purely a retrieval system.

The agentic loop (trelix/agent/

) is CodeAct-style ReAct: instead of one retrieval-then-synthesize pass, the agent can decide it needs another lookup, run it, and fold the result back into its reasoning before answering. Alongside it, trelix/analysis/taint.py

and defuse.py

added real data-flow and taint analysis β€” tracing how a value flows from a source to a sink across function boundaries, which is a different kind of question than "what code is semantically similar to this query."

The other two branches were retrieval-quality work: SPLADE-Code sparse retrieval (trelix/embedder/sparse.py

, trelix/store/sparse_store.py

) gives trelix a learned sparse representation to sit alongside BM25 and dense vectors, and multi-granularity indexing (trelix/indexing/multi_granularity.py

, MGS3-style) means the index isn't forced to choose one chunk size β€” function-level, class-level, and file-level granularities can all be retrieved against.

The most interesting engineering in this window isn't a feature β€” it's a class of failure I preempted instead of debugging in production. DimensionGuard

, added at Retriever.__init__

in v2.3.0, checks embedding provider and dimension at startup and raises DimensionMismatchError

with the exact recovery command (trelix migrate-vectors --reset ) if they don't match what's on disk. Without it, switching from an Azure embedder (3072-dim) to a local model (384-dim) doesn't error β€” it silently returns wrong results, because cosine similarity between mismatched-dimension vectors still computes a number, just not a meaningful one. That's the worst kind of bug: no stack trace, no crash, just quietly bad answers. v2.5.0 (2026-07-06) extended the same guard to FileWatcher.__init__

, so a provider mismatch fails fast at watch startup instead of at query time, days later, when nobody remembers which embedder was configured when.

The MCP surface grew up in the same window. v2.3.0 added MCP Resources (trelix://index/stats

, `trelix://repo/{path}/manifest`

, `trelix://repo/{path}/symbols/{name}`

) and MCP Prompts (`trelix-search`

, trelix-explain

, trelix-blast-radius ) β€” reusable, application-addressable primitives instead of one-off tool calls. v2.5.0 went further: trelix-mcp

now advertises resources.subscribe=True

, and a thread-safe SubscriptionRegistry

tracks who's watching which URI, so notify_file_changed()

can fire notifications/resources/updated

the moment watchfiles

detects a change. That notification path had a gap of its own until v2.7.0 Phase 1 (PR #55): FileWatcher._do_reindex

only fired the notification on hash-identical skips, never on an actual successful re-index β€” the one case where a subscriber genuinely needed to know. The same release added idx_files_rel_path

as an index on files.rel_path

, eliminating a full table scan that GraphUpdater.update_file()

was silently paying on every single file-change event.

DiffReviewer

and trelix review <repo> [--diff] [--base] [--head] (v2.3.0) turned trelix into something you point at a diff, not just a repo β€” it parses git diffs via DiffParser.from_git()

(subprocess with shell=False , no injection surface), turns each hunk into a retrieval query, and generates review comments that are crash-safe by construction: DiffReviewer.review()

never raises. v2.4.0 (2026-07-04) connected that to GitHub directly β€” GitHubPRClient

plus trelix review --pr owner/repo#N --post-comments , authenticating only via GITHUB_TOKEN

, handling all seven GitHub file-status values, and warning past a 3,000-file truncation limit. v2.7.0 Phase 3 (PR #57) closed the loop with .github/workflows/trelix-review.yml

, which runs that same review command on every PR and posts findings as GitHub Check annotations with file and line references β€” continue-on-error: true

on the indexing step, because CI runners without local embedding models shouldn't fail the whole workflow. The same phase shipped workspace-vscode/

, a VS Code extension scaffold with trelix.search

and trelix.ask

commands, talking to the existing trelix-mcp

package over stdio β€” no new backend, just a new front door. The other axis of growth was going multi-repo. RepoRegistry

(v2.3.0) manages ~/.config/trelix/repos.json

, and FederatedRetriever

fans a query out across every registered repo in parallel, RRF-merges the results, and dedupes by (file_path, symbol_id)

β€” crash-safe, returning `[]`

if every repo fails rather than propagating one bad repo's exception. v2.4.0 added a SHA-256-keyed TTL cache (`cache_ttl=120.0`

) tuned for the query patterns of an actual debugging session, where you ask variations of the same question five times in ten minutes. v2.7.0 Phase 2 (PR #56) pushed federation further with make_scip_symbol_id()

β€” stable, SCIP-style cross-repo symbol IDs, sha256-truncated and pipe-separated so scoped npm packages like @scope/pkg

resolve unambiguously β€” and DiffEmbedder

, a CCRep-style (arXiv:2302.03924) before/after body-pair encoder for PR diff hunks. search_similar_diffs() finds historically similar changes via cosine similarity, with a NaN guard and dimension-mismatch protection baked in from day one, because I'd already been burned once by silent dimension corruption.

v2.6.0 (2026-07-08) tackled the two things that get expensive as a codebase grows: recomputing the whole community graph on every file save, and blocking on a full index pass before you can search anything. The DF Louvain frontier heuristic (compute_affected_frontier()

, detect_communities_incremental() , arXiv:2404.19634) reprocesses only the seed nodes, their neighbors, and their existing community members β€” falling back to a full recompute only when the affected frontier exceeds 50% of the graph. TRELIX_INDEXER_STREAMING=true

(v2.7.0 Phase 2) makes indexing itself lazy β€” _iter_files() yields files one at a time into a bounded Queue(maxsize=64)

, with a try/finally

guarantee that the producer sentinel always gets sent even on an exception. It's off by default, and I mean that literally: zero behavior change on the path everyone is actually running.

I also shipped two things I'm not willing to oversell. The XTR late-interaction reranker (NeurIPS 2023, arXiv:2304.01982) is cheaper than ColBERT/PLAID by reusing tokens you already retrieved instead of re every document's full token set β€” that's a genuinely good idea. But it's explicitly marked EXPERIMENTAL in the changelog, it emits a UserWarning

on first use, and it has not been benchmarked against CoIR or CoREB on code-specific retrieval. PLAID stays the production-validated default. Same discipline applies to the GroUSE-inspired synthesis harness (arXiv:2409.06595, COLING 2025) β€” SynthesisEvalHarness

scores hallucination, completeness, and faithfulness across seven failure modes, because I'd been leaning on "does GPT-4 think this answer sounds right" as an implicit quality bar, and that correlation is not a substitute for actually checking whether the citations are real.

Test count tells the same story as the changelog: 929 unit tests at the v1.0.0 baseline, 1,467 unit plus 41 MCP tests β€” 1,508 total β€” by v2.7.0. pip install "trelix[local]"

still gets you a fully offline setup, and the index is still one SQLite file. Growing the surface area from three retrieval legs to seven, plus a knowledge graph, an agentic loop, and federation, didn't require growing the infrastructure footprint at all β€” every new leg, every graph feature, every federation layer is opt-in behind a config flag that defaults to off. That was a deliberate constraint, not an accident, and it's the one I'm least willing to relax as this keeps growing.

── more in #developer-tools 4 stories Β· sorted by recency
── more on @trelix 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain β€” perfect for shipping the agent you just read about.

$git push zahid main
β†’ Live at https://your-agent.zahid.host βœ“
Get free account β†’ Pricing
from €0/mo Β· no card required
LIVE [news/trelix-v1-0-to-v2-7-…] indexed:0 read:9min 2026-07-09 Β· β€”